All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.jface.text.projection.ProjectionDocument Maven / Gradle / Ivy

Go to download

AspectJ tools most notably contains the AspectJ compiler (AJC). AJC applies aspects to Java classes during compilation, fully replacing Javac for plain Java classes and also compiling native AspectJ or annotation-based @AspectJ syntax. Furthermore, AJC can weave aspects into existing class files in a post-compile binary weaving step. This library is a superset of AspectJ weaver and hence also of AspectJ runtime.

There is a newer version: 1.9.22.1
Show newest version
/*******************************************************************************
 * Copyright (c) 2000, 2010 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *     Anton Leherbauer  - [projection] "Backspace" key deleting something else - http://bugs.eclipse.org/301023
 *******************************************************************************/
package org.eclipse.jface.text.projection;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.jface.text.AbstractDocument;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.BadPositionCategoryException;
import org.eclipse.jface.text.DefaultLineTracker;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentExtension;
import org.eclipse.jface.text.IDocumentInformationMapping;
import org.eclipse.jface.text.IDocumentListener;
import org.eclipse.jface.text.ILineTracker;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextStore;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.TextUtilities;


/**
 * A ProjectionDocument 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.
 * 

* The projection document indirectly utilizes its master document as * ITextStore by means of a ProjectionTextStore. *

* 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 addMasterDocumentRange * and removeMasterDocumentRange are provided. For any * manipulation, the projection document sends out a * {@link org.eclipse.jface.text.projection.ProjectionDocumentEvent} describing * the change. *

* Clients are not supposed to directly instantiate this class. In order to * obtain a projection document, a * {@link org.eclipse.jface.text.projection.ProjectionDocumentManager}should be * used. This class is not intended to be subclassed outside of its origin * package.

* * @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 extends 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 final 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 final 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 boolean fIsUpdating= false; /** Indicated whether the projection document is in auto expand mode nor not */ private boolean 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 ProjectionDocument(IDocument masterDocument) { super(); fMasterDocument= masterDocument; if (fMasterDocument instanceof IDocumentExtension) fMasterDocumentExtension= (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()} */ @Deprecated 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; } @Override 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 (Position f : fragments) { Fragment fragment = (Fragment) f; 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) throws BadLocationException, BadPositionCategoryException { int offset= 0; if (index > 0) { Position[] segments= getSegments(); Segment segment= (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 null if none * @throws BadLocationException if the given range is invalid in the master * document */ private void internalAddMasterDocumentRange(int offsetInMaster, int lengthInMaster, DocumentEvent masterDocumentEvent) throws BadLocationException { if (lengthInMaster == 0) return; try { Position[] fragments= getFragments(); int index= fMasterDocument.computeIndexInCategory(fFragmentsCategory, offsetInMaster); Fragment left= null; Fragment right= null; if (index < fragments.length) { Fragment fragment= (Fragment) fragments[index]; if (offsetInMaster == fragment.offset) if (fragment.length == 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 == fragment.offset) right= fragment; } if (0 < index && index <= fragments.length) { Fragment fragment= (Fragment) fragments[index - 1]; if (fragment.includes(offsetInMaster)) throw new IllegalArgumentException("overlaps with existing fragment"); //$NON-NLS-1$ if (fragment.getOffset() + fragment.getLength() == offsetInMaster) left= fragment; } int offsetInSlave= 0; if (index > 0) { Fragment fragment= (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 != null && right != 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 != null) { int endOffset= offsetInMaster +lengthInMaster; left.setLength(endOffset - left.getOffset()); left.segment.markForStretch(); } else if (right != 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 (Position fragment : fragments) { Fragment f = (Fragment) fragment; 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) throws BadLocationException { try { IRegion imageRegion= fMapping.toExactImageRegion(new Region(offsetInMaster, lengthInMaster)); if (imageRegion == null) throw new IllegalArgumentException(); Fragment fragment= findFragment(offsetInMaster, lengthInMaster); if (fragment == null) throw new IllegalArgumentException(); ProjectionDocumentEvent event= new ProjectionDocumentEvent(this, imageRegion.getOffset(), imageRegion.getLength(), "", offsetInMaster, lengthInMaster); //$NON-NLS-1$ super.fireDocumentAboutToBeChanged(event); if (fragment.getOffset() == offsetInMaster) { fragment.setOffset(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) throws BadLocationException { IRegion[] fragments= null; IRegion imageRegion= fMapping.toImageRegion(new Region(offsetInMaster, lengthInMaster)); if (imageRegion != null) fragments= fMapping.toExactOriginRegions(imageRegion); if (fragments == null || fragments.length == 0) return new IRegion[] { 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) throws BadLocationException { IRegion[] fragments= null; IRegion imageRegion= fMapping.toImageRegion(new Region(offsetInMaster, lengthInMaster)); if (imageRegion != null) fragments= fMapping.toExactOriginRegions(imageRegion); if (fragments == null || fragments.length == 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) throws BadLocationException { 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 null if none * @throws BadLocationException in case the master event is not valid */ private void addMasterDocumentRange(int offsetInMaster, int lengthInMaster, DocumentEvent masterDocumentEvent) throws BadLocationException { /* * 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 == 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) throws BadLocationException { IRegion[] fragments= computeProjectedMasterRegions(offsetInMaster, lengthInMaster); if (fragments == null || fragments.length == 0) return; for (IRegion fragment : fragments) { 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 null 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 null * @throws BadLocationException in case the given range is invalid in the master document */ public final IRegion[] computeProjectedMasterRegions(int offsetInMaster, int lengthInMaster) throws BadLocationException { IRegion imageRegion= fMapping.toImageRegion(new Region(offsetInMaster, lengthInMaster)); return imageRegion != null ? fMapping.toExactOriginRegions(imageRegion) : null; } /** * Returns whether this projection is being updated. * * @return true if the document is updating */ protected boolean isUpdating() { return fIsUpdating; } @Override public void replace(int offset, int length, String text) throws BadLocationException { try { fIsUpdating= true; if (fMasterDocumentExtension != null) fMasterDocumentExtension.stopPostNotificationProcessing(); super.replace(offset, length, text); } finally { fIsUpdating= false; if (fMasterDocumentExtension != null) fMasterDocumentExtension.resumePostNotificationProcessing(); } } @Override public void set(String text) { try { fIsUpdating= true; if (fMasterDocumentExtension != null) fMasterDocumentExtension.stopPostNotificationProcessing(); super.set(text); } finally { fIsUpdating= false; if (fMasterDocumentExtension != 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) throws BadLocationException { if (!isUpdating()) { IRegion imageRegion= fMapping.toExactImageRegion(new Region(masterEvent.getOffset(), masterEvent.getLength())); if (imageRegion != 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 true if masterEvent affects this projection document * @throws BadLocationException in case the master event is not valid */ protected final boolean adaptProjectionToMasterChange(DocumentEvent masterEvent) throws BadLocationException { if (!isUpdating() && fFragmentsUpdater.affectsPositions(masterEvent) || fIsAutoExpanding && masterEvent.getLength() > 0) { addMasterDocumentRange(masterEvent.getOffset(), masterEvent.getLength(), masterEvent); return true; } else if (fMapping.getImageLength() == 0 && masterEvent.getLength() == 0) { Position[] fragments= getFragments(); if (fragments.length == 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 { boolean assertNotNull= adaptProjectionToMasterChange(masterEvent); fSlaveEvent= normalize(masterEvent); if (assertNotNull && fSlaveEvent == null) internalError(); fMasterEvent= masterEvent; if (fSlaveEvent != 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 == fMasterEvent) { if (fSlaveEvent != null) { try { getTracker().replace(fSlaveEvent.getOffset(), fSlaveEvent.getLength(), fSlaveEvent.getText()); fireDocumentChanged(fSlaveEvent); } catch (BadLocationException e) { internalError(); } } else if (ensureWellFormedSegmentation(masterEvent.getOffset())) fMapping.projectionChanged(); } } @Override 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 */ @Override protected void fireDocumentChanged(DocumentEvent event) { super.fireDocumentChanged(fSlaveEvent); } @Override protected void updateDocumentStructures(DocumentEvent event) { super.updateDocumentStructures(event); ensureWellFormedSegmentation(computeAnchor(event)); fMapping.projectionChanged(); } private int computeAnchor(DocumentEvent event) { if (event instanceof ProjectionDocumentEvent) { ProjectionDocumentEvent slave= (ProjectionDocumentEvent) event; Object changeType= slave.getChangeType(); if (ProjectionDocumentEvent.CONTENT_CHANGE == changeType) { DocumentEvent master= slave.getMasterEvent(); if (master != null) return master.getOffset(); } else if (ProjectionDocumentEvent.PROJECTION_CHANGE == changeType) { return slave.getMasterOffset(); } } return -1; } private boolean ensureWellFormedSegmentation(int anchorOffset) { boolean changed= false; Position[] segments= getSegments(); for (int i= 0; i < segments.length; i++) { Segment segment= (Segment) segments[i]; if (segment.isDeleted() || (segment.getLength() == 0 && (i < segments.length - 1 || (i > 0 && segments[i - 1].isDeleted())))) { try { removePosition(fSegmentsCategory, segment); fMasterDocument.removePosition(fFragmentsCategory, segment.fragment); changed= true; } catch (BadPositionCategoryException e) { internalError(); } } else if (i < segments.length - 1) { Segment next= (Segment) segments[i + 1]; if (next.isDeleted() || next.getLength() == 0) continue; Fragment fragment= segment.fragment; if (fragment.getOffset() + fragment.getLength() == 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 != -1) { Position[] changedSegments= getSegments(); if (changedSegments == null || changedSegments.length == 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; } @Override 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 true if auto-expanding */ public void setAutoExpandMode(boolean 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) throws BadLocationException { try { ProjectionDocumentEvent event= new ProjectionDocumentEvent(this, 0, fMapping.getImageLength(), fMasterDocument.get(offsetInMaster, lengthInMaster), offsetInMaster, lengthInMaster); super.fireDocumentAboutToBeChanged(event); Position[] fragments= getFragments(); for (Position fragment1 : fragments) { Fragment fragment = (Fragment) fragment1; 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(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy