Mercurial > projects > dwt-addons
view dwtx/jface/text/projection/ProjectionDocument.d @ 153:f70d9508c95c
Fix java Collection imports
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Mon, 25 Aug 2008 00:27:31 +0200 |
parents | 75302ef3f92f |
children | 3678e4f1a766 |
line wrap: on
line source
/******************************************************************************* * Copyright (c) 2000, 2008 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.projection.ProjectionDocument; import dwtx.jface.text.projection.ProjectionMapping; // packageimport import dwtx.jface.text.projection.ChildDocumentManager; // packageimport import dwtx.jface.text.projection.SegmentUpdater; // packageimport import dwtx.jface.text.projection.Segment; // packageimport import dwtx.jface.text.projection.FragmentUpdater; // packageimport import dwtx.jface.text.projection.ProjectionDocumentEvent; // packageimport import dwtx.jface.text.projection.ChildDocument; // packageimport import dwtx.jface.text.projection.IMinimalMapping; // packageimport import dwtx.jface.text.projection.Fragment; // packageimport import dwtx.jface.text.projection.ProjectionTextStore; // packageimport import dwtx.jface.text.projection.ProjectionDocumentManager; // packageimport import dwt.dwthelper.utils; import dwtx.dwtxhelper.Collection; import dwtx.jface.text.AbstractDocument; import dwtx.jface.text.BadLocationException; import dwtx.jface.text.BadPositionCategoryException; import dwtx.jface.text.DefaultLineTracker; import dwtx.jface.text.DocumentEvent; import dwtx.jface.text.IDocument; import dwtx.jface.text.IDocumentExtension; import dwtx.jface.text.IDocumentInformationMapping; import dwtx.jface.text.IDocumentListener; import dwtx.jface.text.ILineTracker; import dwtx.jface.text.IRegion; import dwtx.jface.text.ITextStore; import dwtx.jface.text.Position; import dwtx.jface.text.Region; import dwtx.jface.text.TextUtilities; /** * A <code>ProjectionDocument</code> represents a projection of its master * document. The contents of a projection document is a sequence of fragments of * the master document, i.e. the projection document can be thought as being * constructed from the master document by not copying the whole master document * but omitting several ranges of the master document. * <p> * The projection document indirectly utilizes its master document as * <code>ITextStore</code> by means of a <code>ProjectionTextStore</code>. * <p> * The content of a projection document can be changed in two ways. Either by a * text replace applied to the master document or the projection document. Or by * changing the projection between the master document and the projection * document. For the latter the two methods <code>addMasterDocumentRange</code> * and <code>removeMasterDocumentRange</code> are provided. For any * manipulation, the projection document sends out a * {@link dwtx.jface.text.projection.ProjectionDocumentEvent} describing * the change. * <p> * Clients are not supposed to directly instantiate this class. In order to * obtain a projection document, a * {@link dwtx.jface.text.projection.ProjectionDocumentManager}should be * used. This class is not intended to be subclassed outside of its origin * package.</p> * * @since 3.0 * @noinstantiate This class is not intended to be instantiated by clients. * @noextend This class is not intended to be subclassed by clients. */ public class ProjectionDocument : AbstractDocument { /** * Prefix of the name of the position category used to keep track of the master * document's fragments that correspond to the segments of the projection * document. */ private const static String FRAGMENTS_CATEGORY_PREFIX= "__fragmentsCategory"; //$NON-NLS-1$ /** * Name of the position category used to keep track of the project * document's segments that correspond to the fragments of the master * document. */ private const static String SEGMENTS_CATEGORY= "__segmentsCategory"; //$NON-NLS-1$ /** The master document */ private IDocument fMasterDocument; /** The master document as document extension */ private IDocumentExtension fMasterDocumentExtension; /** The fragments' position category */ private String fFragmentsCategory; /** The segment's position category */ private String fSegmentsCategory; /** The document event issued by the master document */ private DocumentEvent fMasterEvent; /** The document event to be issued by the projection document */ private ProjectionDocumentEvent fSlaveEvent; /** The original document event generated by a direct manipulation of this projection document */ private DocumentEvent fOriginalEvent; /** Indicates whether the projection document initiated a master document update or not */ private bool fIsUpdating= false; /** Indicated whether the projection document is in auto expand mode nor not */ private bool fIsAutoExpanding= false; /** The position updater for the segments */ private SegmentUpdater fSegmentUpdater; /** The position updater for the fragments */ private FragmentUpdater fFragmentsUpdater; /** The projection mapping */ private ProjectionMapping fMapping; /** * Creates a projection document for the given master document. * * @param masterDocument the master document */ public this(IDocument masterDocument) { super(); fMasterDocument= masterDocument; if ( cast(IDocumentExtension)fMasterDocument ) fMasterDocumentExtension= cast(IDocumentExtension) fMasterDocument; fSegmentsCategory= SEGMENTS_CATEGORY; fFragmentsCategory= FRAGMENTS_CATEGORY_PREFIX + hashCode(); fMasterDocument.addPositionCategory(fFragmentsCategory); fFragmentsUpdater= new FragmentUpdater(fFragmentsCategory); fMasterDocument.addPositionUpdater(fFragmentsUpdater); fMapping= new ProjectionMapping(masterDocument, fFragmentsCategory, this, fSegmentsCategory); ITextStore s= new ProjectionTextStore(masterDocument, fMapping); ILineTracker tracker= new DefaultLineTracker(); setTextStore(s); setLineTracker(tracker); completeInitialization(); initializeProjection(); tracker.set(s.get(0, s.getLength())); } /** * Disposes this projection document. */ public void dispose() { fMasterDocument.removePositionUpdater(fFragmentsUpdater); try { fMasterDocument.removePositionCategory(fFragmentsCategory); } catch (BadPositionCategoryException x) { // allow multiple dispose calls } } private void internalError() { throw new IllegalStateException(); } /** * Returns the fragments of the master documents. * * @return the fragment of the master document */ protected final Position[] getFragments() { try { return fMasterDocument.getPositions(fFragmentsCategory); } catch (BadPositionCategoryException e) { internalError(); } // unreachable return null; } /** * Returns the segments of this projection document. * * @return the segments of this projection document */ protected final Position[] getSegments() { try { return getPositions(fSegmentsCategory); } catch (BadPositionCategoryException e) { internalError(); } // unreachable return null; } /** * Returns the projection mapping used by this document. * * @return the projection mapping used by this document * @deprecated As of 3.4, replaced by {@link #getDocumentInformationMapping()} */ public ProjectionMapping getProjectionMapping(){ return fMapping; } /** * Returns the projection mapping used by this document. * * @return the projection mapping used by this document * @since 3.4 */ public IDocumentInformationMapping getDocumentInformationMapping() { return fMapping; } /** * Returns the master document of this projection document. * * @return the master document of this projection document */ public IDocument getMasterDocument() { return fMasterDocument; } /* * @see dwtx.jface.text.IDocumentExtension4#getDefaultLineDelimiter() * @since 3.1 */ public String getDefaultLineDelimiter() { return TextUtilities.getDefaultLineDelimiter(fMasterDocument); } /** * Initializes the projection document from the master document based on * the master's fragments. */ private void initializeProjection() { try { addPositionCategory(fSegmentsCategory); fSegmentUpdater= new SegmentUpdater(fSegmentsCategory); addPositionUpdater(fSegmentUpdater); int offset= 0; Position[] fragments= getFragments(); for (int i= 0; i < fragments.length; i++) { Fragment fragment= cast(Fragment) fragments[i]; Segment segment= new Segment(offset, fragment.getLength()); segment.fragment= fragment; addPosition(fSegmentsCategory, segment); offset += fragment.length; } } catch (BadPositionCategoryException x) { internalError(); } catch (BadLocationException x) { internalError(); } } /** * Creates a segment for the given fragment at the given position inside the list of segments. * * @param fragment the corresponding fragment * @param index the index in the list of segments * @return the created segment * @throws BadLocationException in case the fragment is invalid * @throws BadPositionCategoryException in case the segment category is invalid */ private Segment createSegmentFor(Fragment fragment, int index) { int offset= 0; if (index > 0) { Position[] segments= getSegments(); Segment segment= cast(Segment) segments[index - 1]; offset= segment.getOffset() + segment.getLength(); } Segment segment= new Segment(offset, 0); segment.fragment= fragment; fragment.segment= segment; addPosition(fSegmentsCategory, segment); return segment; } /** * Adds the given range of the master document to this projection document. * * @param offsetInMaster offset of the master document range * @param lengthInMaster length of the master document range * @param masterDocumentEvent the master document event that causes this * projection change or <code>null</code> if none * @throws BadLocationException if the given range is invalid in the master * document */ private void internalAddMasterDocumentRange(int offsetInMaster, int lengthInMaster, DocumentEvent masterDocumentEvent) { if (lengthInMaster is 0) return; try { Position[] fragments= getFragments(); int index= fMasterDocument.computeIndexInCategory(fFragmentsCategory, offsetInMaster); Fragment left= null; Fragment right= null; if (index < fragments.length) { Fragment fragment= cast(Fragment) fragments[index]; if (offsetInMaster is fragment.offset) if (fragment.length is 0) // the fragment does not overlap - it is a zero-length fragment at the same offset left= fragment; else throw new IllegalArgumentException("overlaps with existing fragment"); //$NON-NLS-1$ if (offsetInMaster + lengthInMaster is fragment.offset) right= fragment; } if (0 < index && index <= fragments.length) { Fragment fragment= cast(Fragment) fragments[index - 1]; if (fragment.includes(offsetInMaster)) throw new IllegalArgumentException("overlaps with existing fragment"); //$NON-NLS-1$ if (fragment.getOffset() + fragment.getLength() is offsetInMaster) left= fragment; } int offsetInSlave= 0; if (index > 0) { Fragment fragment= cast(Fragment) fragments[index - 1]; Segment segment= fragment.segment; offsetInSlave= segment.getOffset() + segment.getLength(); } ProjectionDocumentEvent event= new ProjectionDocumentEvent(this, offsetInSlave, 0, fMasterDocument.get(offsetInMaster, lengthInMaster), offsetInMaster, lengthInMaster, masterDocumentEvent); super.fireDocumentAboutToBeChanged(event); // check for neighboring fragment if (left !is null && right !is null) { int endOffset= right.getOffset() + right.getLength(); left.setLength(endOffset - left.getOffset()); left.segment.setLength(left.segment.getLength() + right.segment.getLength()); removePosition(fSegmentsCategory, right.segment); fMasterDocument.removePosition(fFragmentsCategory, right); } else if (left !is null) { int endOffset= offsetInMaster +lengthInMaster; left.setLength(endOffset - left.getOffset()); left.segment.markForStretch(); } else if (right !is null) { right.setOffset(right.getOffset() - lengthInMaster); right.setLength(right.getLength() + lengthInMaster); right.segment.markForStretch(); } else { // create a new segment Fragment fragment= new Fragment(offsetInMaster, lengthInMaster); fMasterDocument.addPosition(fFragmentsCategory, fragment); Segment segment= createSegmentFor(fragment, index); segment.markForStretch(); } getTracker().replace(event.getOffset(), event.getLength(), event.getText()); super.fireDocumentChanged(event); } catch (BadPositionCategoryException x) { internalError(); } } /** * Finds the fragment of the master document that represents the given range. * * @param offsetInMaster the offset of the range in the master document * @param lengthInMaster the length of the range in the master document * @return the fragment representing the given master document range */ private Fragment findFragment(int offsetInMaster, int lengthInMaster) { Position[] fragments= getFragments(); for (int i= 0; i < fragments.length; i++) { Fragment f= cast(Fragment) fragments[i]; if (f.getOffset() <= offsetInMaster && offsetInMaster + lengthInMaster <= f.getOffset() + f.getLength()) return f; } return null; } /** * Removes the given range of the master document from this projection * document. * * @param offsetInMaster the offset of the range in the master document * @param lengthInMaster the length of the range in the master document * * @throws BadLocationException if the given range is not valid in the * master document * @throws IllegalArgumentException if the given range is not projected in * this projection document or is not completely comprised by * an existing fragment */ private void internalRemoveMasterDocumentRange(int offsetInMaster, int lengthInMaster) { try { IRegion imageRegion= fMapping.toExactImageRegion(new Region(offsetInMaster, lengthInMaster)); if (imageRegion is null) throw new IllegalArgumentException(); Fragment fragment= findFragment(offsetInMaster, lengthInMaster); if (fragment is null) throw new IllegalArgumentException(); ProjectionDocumentEvent event= new ProjectionDocumentEvent(this, imageRegion.getOffset(), imageRegion.getLength(), "", offsetInMaster, lengthInMaster); //$NON-NLS-1$ super.fireDocumentAboutToBeChanged(event); if (fragment.getOffset() is offsetInMaster) { fragment.setOffset(offsetInMaster + lengthInMaster); fragment.setLength(fragment.getLength() - lengthInMaster); } else if (fragment.getOffset() + fragment.getLength() is offsetInMaster + lengthInMaster) { fragment.setLength(fragment.getLength() - lengthInMaster); } else { // split fragment into three fragments, let position updater remove it // add fragment for the region to be removed Fragment newFragment= new Fragment(offsetInMaster, lengthInMaster); Segment segment= new Segment(imageRegion.getOffset(), imageRegion.getLength()); newFragment.segment= segment; segment.fragment= newFragment; fMasterDocument.addPosition(fFragmentsCategory, newFragment); addPosition(fSegmentsCategory, segment); // add fragment for the remainder right of the deleted range in the original fragment int offset= offsetInMaster + lengthInMaster; newFragment= new Fragment(offset, fragment.getOffset() + fragment.getLength() - offset); offset= imageRegion.getOffset() + imageRegion.getLength(); segment= new Segment(offset, fragment.segment.getOffset() + fragment.segment.getLength() - offset); newFragment.segment= segment; segment.fragment= newFragment; fMasterDocument.addPosition(fFragmentsCategory, newFragment); addPosition(fSegmentsCategory, segment); // adjust length of initial fragment (the left one) fragment.setLength(offsetInMaster - fragment.getOffset()); fragment.segment.setLength(imageRegion.getOffset() - fragment.segment.getOffset()); } getTracker().replace(event.getOffset(), event.getLength(), event.getText()); super.fireDocumentChanged(event); } catch (BadPositionCategoryException x) { internalError(); } } /** * Returns the sequence of all master document regions which are contained * in the given master document range and which are not yet part of this * projection document. * * @param offsetInMaster the range offset in the master document * @param lengthInMaster the range length in the master document * @return the sequence of regions which are not yet part of the projection * document * @throws BadLocationException in case the given range is invalid in the * master document */ public final IRegion[] computeUnprojectedMasterRegions(int offsetInMaster, int lengthInMaster) { IRegion[] fragments= null; IRegion imageRegion= fMapping.toImageRegion(new Region(offsetInMaster, lengthInMaster)); if (imageRegion !is null) fragments= fMapping.toExactOriginRegions(imageRegion); if (fragments is null || fragments.length is 0) return [ new Region(offsetInMaster, lengthInMaster) ]; List gaps= new ArrayList(); IRegion region= fragments[0]; if (offsetInMaster < region.getOffset()) gaps.add(new Region(offsetInMaster, region.getOffset() - offsetInMaster)); for (int i= 0; i < fragments.length - 1; i++) { IRegion left= fragments[i]; IRegion right= fragments[i + 1]; int leftEnd= left.getOffset() + left.getLength(); if (leftEnd < right.getOffset()) gaps.add(new Region(leftEnd, right.getOffset() - leftEnd)); } region= fragments[fragments.length - 1]; int leftEnd= region.getOffset() + region.getLength(); int rightEnd= offsetInMaster + lengthInMaster; if (leftEnd < rightEnd) gaps.add(new Region(leftEnd, rightEnd - leftEnd)); IRegion[] result= new IRegion[gaps.size()]; gaps.toArray(result); return result; } /** * Returns the first master document region which is contained in the given * master document range and which is not yet part of this projection * document. * * @param offsetInMaster the range offset in the master document * @param lengthInMaster the range length in the master document * @return the first region that is not yet part of the projection document * @throws BadLocationException in case the given range is invalid in the * master document * @since 3.1 */ private IRegion computeFirstUnprojectedMasterRegion(int offsetInMaster, int lengthInMaster) { IRegion[] fragments= null; IRegion imageRegion= fMapping.toImageRegion(new Region(offsetInMaster, lengthInMaster)); if (imageRegion !is null) fragments= fMapping.toExactOriginRegions(imageRegion); if (fragments is null || fragments.length is 0) return new Region(offsetInMaster, lengthInMaster); IRegion region= fragments[0]; if (offsetInMaster < region.getOffset()) return new Region(offsetInMaster, region.getOffset() - offsetInMaster); for (int i= 0; i < fragments.length - 1; i++) { IRegion left= fragments[i]; IRegion right= fragments[i + 1]; int leftEnd= left.getOffset() + left.getLength(); if (leftEnd < right.getOffset()) return new Region(leftEnd, right.getOffset() - leftEnd); } region= fragments[fragments.length - 1]; int leftEnd= region.getOffset() + region.getLength(); int rightEnd= offsetInMaster + lengthInMaster; if (leftEnd < rightEnd) return new Region(leftEnd, rightEnd - leftEnd); return null; } /** * Ensures that the given range of the master document is part of this * projection document. * * @param offsetInMaster the offset of the master document range * @param lengthInMaster the length of the master document range * @throws BadLocationException in case the master event is not valid */ public void addMasterDocumentRange(int offsetInMaster, int lengthInMaster) { addMasterDocumentRange(offsetInMaster, lengthInMaster, null); } /** * Ensures that the given range of the master document is part of this * projection document. * * @param offsetInMaster the offset of the master document range * @param lengthInMaster the length of the master document range * @param masterDocumentEvent the master document event which causes this * projection change, or <code>null</code> if none * @throws BadLocationException in case the master event is not valid */ private void addMasterDocumentRange(int offsetInMaster, int lengthInMaster, DocumentEvent masterDocumentEvent) { /* * Calling internalAddMasterDocumentRange may cause other master ranges * to become unfolded, resulting in re-entrant calls to this method. In * order to not add a region twice, we have to compute the next region * to add in every iteration. * * To place an upper bound on the number of iterations, we use the number * of fragments * 2 as the limit. */ int limit= Math.max(getFragments().length * 2, 20); while (true) { if (limit-- < 0) throw new IllegalArgumentException("safety loop termination"); //$NON-NLS-1$ IRegion gap= computeFirstUnprojectedMasterRegion(offsetInMaster, lengthInMaster); if (gap is null) return; internalAddMasterDocumentRange(gap.getOffset(), gap.getLength(), masterDocumentEvent); } } /** * Ensures that the given range of the master document is not part of this * projection document. * * @param offsetInMaster the offset of the master document range * @param lengthInMaster the length of the master document range * @throws BadLocationException in case the master event is not valid */ public void removeMasterDocumentRange(int offsetInMaster, int lengthInMaster) { IRegion[] fragments= computeProjectedMasterRegions(offsetInMaster, lengthInMaster); if (fragments is null || fragments.length is 0) return; for (int i= 0; i < fragments.length; i++) { IRegion fragment= fragments[i]; internalRemoveMasterDocumentRange(fragment.getOffset(), fragment.getLength()); } } /** * Returns the sequence of all master document regions with are contained in the given master document * range and which are part of this projection document. May return <code>null</code> if no such * regions exist. * * @param offsetInMaster the range offset in the master document * @param lengthInMaster the range length in the master document * @return the sequence of regions which are part of the projection document or <code>null</code> * @throws BadLocationException in case the given range is invalid in the master document */ public final IRegion[] computeProjectedMasterRegions(int offsetInMaster, int lengthInMaster) { IRegion imageRegion= fMapping.toImageRegion(new Region(offsetInMaster, lengthInMaster)); return imageRegion !is null ? fMapping.toExactOriginRegions(imageRegion) : null; } /** * Returns whether this projection is being updated. * * @return <code>true</code> if the document is updating */ protected bool isUpdating() { return fIsUpdating; } /* * @see dwtx.jface.text.IDocument#replace(int, int, java.lang.String) */ public void replace(int offset, int length, String text) { try { fIsUpdating= true; if (fMasterDocumentExtension !is null) fMasterDocumentExtension.stopPostNotificationProcessing(); super.replace(offset, length, text); } finally { fIsUpdating= false; if (fMasterDocumentExtension !is null) fMasterDocumentExtension.resumePostNotificationProcessing(); } } /* * @see dwtx.jface.text.IDocument#set(java.lang.String) */ public void set(String text) { try { fIsUpdating= true; if (fMasterDocumentExtension !is null) fMasterDocumentExtension.stopPostNotificationProcessing(); super.set(text); } finally { fIsUpdating= false; if (fMasterDocumentExtension !is null) fMasterDocumentExtension.resumePostNotificationProcessing(); } } /** * Transforms a document event of the master document into a projection * document based document event. * * @param masterEvent the master document event * @return the slave document event * @throws BadLocationException in case the master event is not valid */ private ProjectionDocumentEvent normalize(DocumentEvent masterEvent) { if (!isUpdating()) { IRegion imageRegion= fMapping.toExactImageRegion(new Region(masterEvent.getOffset(), masterEvent.getLength())); if (imageRegion !is null) return new ProjectionDocumentEvent(this, imageRegion.getOffset(), imageRegion.getLength(), masterEvent.getText(), masterEvent); return null; } ProjectionDocumentEvent event= new ProjectionDocumentEvent(this, fOriginalEvent.getOffset(), fOriginalEvent.getLength(), fOriginalEvent.getText(), masterEvent); fOriginalEvent= null; return event; } /** * Ensures that when the master event affects this projection document, that the whole region described by the * event is part of this projection document. * * @param masterEvent the master document event * @return <code>true</code> if masterEvent affects this projection document * @throws BadLocationException in case the master event is not valid */ protected final bool adaptProjectionToMasterChange(DocumentEvent masterEvent) { if (!isUpdating() && fFragmentsUpdater.affectsPositions(masterEvent) || fIsAutoExpanding && masterEvent.getLength() > 0) { addMasterDocumentRange(masterEvent.getOffset(), masterEvent.getLength(), masterEvent); return true; } else if (fMapping.getImageLength() is 0 && masterEvent.getLength() is 0) { Position[] fragments= getFragments(); if (fragments.length is 0) { // there is no segment in this projection document, thus one must be created // need to bypass the usual infrastructure as the new segment/fragment would be of length 0 and thus the segmentation be not well formed try { Fragment fragment= new Fragment(0, 0); fMasterDocument.addPosition(fFragmentsCategory, fragment); createSegmentFor(fragment, 0); } catch (BadPositionCategoryException x) { internalError(); } } } return isUpdating(); } /** * When called, this projection document is informed about a forthcoming * change of its master document. This projection document checks whether * the master document change affects it and if so informs all document * listeners. * * @param masterEvent the master document event */ public void masterDocumentAboutToBeChanged(DocumentEvent masterEvent) { try { bool assertNotNull= adaptProjectionToMasterChange(masterEvent); fSlaveEvent= normalize(masterEvent); if (assertNotNull && fSlaveEvent is null) internalError(); fMasterEvent= masterEvent; if (fSlaveEvent !is null) delayedFireDocumentAboutToBeChanged(); } catch (BadLocationException e) { internalError(); } } /** * When called, this projection document is informed about a change of its * master document. If this projection document is affected it informs all * of its document listeners. * * @param masterEvent the master document event */ public void masterDocumentChanged(DocumentEvent masterEvent) { if ( !isUpdating() && masterEvent is fMasterEvent) { if (fSlaveEvent !is null) { try { getTracker().replace(fSlaveEvent.getOffset(), fSlaveEvent.getLength(), fSlaveEvent.getText()); fireDocumentChanged(fSlaveEvent); } catch (BadLocationException e) { internalError(); } } else if (ensureWellFormedSegmentation(masterEvent.getOffset())) fMapping.projectionChanged(); } } /* * @see dwtx.jface.text.AbstractDocument#fireDocumentAboutToBeChanged(dwtx.jface.text.DocumentEvent) */ protected void fireDocumentAboutToBeChanged(DocumentEvent event) { fOriginalEvent= event; // delay it until there is a notification from the master document // at this point, it is expensive to construct the master document information } /** * Fires the slave document event as about-to-be-changed event to all registered listeners. */ private void delayedFireDocumentAboutToBeChanged() { super.fireDocumentAboutToBeChanged(fSlaveEvent); } /** * Ignores the given event and sends the semantically equal slave document event instead. * * @param event the event to be ignored */ protected void fireDocumentChanged(DocumentEvent event) { super.fireDocumentChanged(fSlaveEvent); } /* * @see dwtx.jface.text.AbstractDocument#updateDocumentStructures(dwtx.jface.text.DocumentEvent) */ protected void updateDocumentStructures(DocumentEvent event) { super.updateDocumentStructures(event); ensureWellFormedSegmentation(computeAnchor(event)); fMapping.projectionChanged(); } private int computeAnchor(DocumentEvent event) { if ( cast(ProjectionDocumentEvent)event ) { ProjectionDocumentEvent slave= cast(ProjectionDocumentEvent) event; Object changeType= slave.getChangeType(); if (ProjectionDocumentEvent.CONTENT_CHANGE is changeType) { DocumentEvent master= slave.getMasterEvent(); if (master !is null) return master.getOffset(); } else if (ProjectionDocumentEvent.PROJECTION_CHANGE is changeType) { return slave.getMasterOffset(); } } return -1; } private bool ensureWellFormedSegmentation(int anchorOffset) { bool changed= false; Position[] segments= getSegments(); for (int i= 0; i < segments.length; i++) { Segment segment= cast(Segment) segments[i]; if (segment.isDeleted() || segment.getLength() is 0) { try { removePosition(fSegmentsCategory, segment); fMasterDocument.removePosition(fFragmentsCategory, segment.fragment); changed= true; } catch (BadPositionCategoryException e) { internalError(); } } else if (i < segments.length - 1) { Segment next= cast(Segment) segments[i + 1]; if (next.isDeleted() || next.getLength() is 0) continue; Fragment fragment= segment.fragment; if (fragment.getOffset() + fragment.getLength() is next.fragment.getOffset()) { // join fragments and their corresponding segments segment.setLength(segment.getLength() + next.getLength()); fragment.setLength(fragment.getLength() + next.fragment.getLength()); next.delete_(); } } } if (changed && anchorOffset !is -1) { Position[] changedSegments= getSegments(); if (changedSegments is null || changedSegments.length is 0) { Fragment fragment= new Fragment(anchorOffset, 0); try { fMasterDocument.addPosition(fFragmentsCategory, fragment); createSegmentFor(fragment, 0); } catch (BadLocationException e) { internalError(); } catch (BadPositionCategoryException e) { internalError(); } } } return changed; } /* * @see IDocumentExtension#registerPostNotificationReplace(IDocumentListener, IDocumentExtension.IReplace) */ public void registerPostNotificationReplace(IDocumentListener owner, IDocumentExtension.IReplace replace) { if (!isUpdating()) throw new UnsupportedOperationException(); super.registerPostNotificationReplace(owner, replace); } /** * Sets the auto expand mode for this document. * * @param autoExpandMode <code>true</code> if auto-expanding */ public void setAutoExpandMode(bool autoExpandMode) { fIsAutoExpanding= autoExpandMode; } /** * Replaces all master document ranges with the given master document range. * * @param offsetInMaster the offset in the master document * @param lengthInMaster the length in the master document * @throws BadLocationException if the given range of the master document is not valid */ public void replaceMasterDocumentRanges(int offsetInMaster, int lengthInMaster) { try { ProjectionDocumentEvent event= new ProjectionDocumentEvent(this, 0, fMapping.getImageLength(), fMasterDocument.get(offsetInMaster, lengthInMaster), offsetInMaster, lengthInMaster); super.fireDocumentAboutToBeChanged(event); Position[] fragments= getFragments(); for (int i= 0; i < fragments.length; i++) { Fragment fragment= cast(Fragment) fragments[i]; fMasterDocument.removePosition(fFragmentsCategory, fragment); removePosition(fSegmentsCategory, fragment.segment); } Fragment fragment= new Fragment(offsetInMaster, lengthInMaster); Segment segment= new Segment(0, 0); segment.fragment= fragment; fragment.segment= segment; fMasterDocument.addPosition(fFragmentsCategory, fragment); addPosition(fSegmentsCategory, segment); getTracker().set(fMasterDocument.get(offsetInMaster, lengthInMaster)); super.fireDocumentChanged(event); } catch (BadPositionCategoryException x) { internalError(); } } }