| /******************************************************************************* |
| * Copyright (c) 2000, 2003 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Common Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/cpl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.jface.text; |
| |
| import java.util.Arrays; |
| import java.util.Comparator; |
| |
| |
| |
| /** |
| * 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 by omitting serveral ranges of the master document. <p> |
| * The projection document utilizes its master document as <code>ITextStore</code>.<p> |
| * This class if for internal use only. |
| * |
| * @since 2.1 |
| * @deprecated |
| */ |
| public final class ProjectionDocument extends AbstractDocument { |
| |
| /** The position category used by <code>ProjectionDocument</code>s to manage the fragments they consist of. */ |
| final public static String FRAGMENT_CATEGORY= "__fragment_category"; //$NON-NLS-1$ |
| |
| /** The parent document */ |
| private IDocument fParentDocument; |
| /** The parent document as document extension */ |
| private IDocumentExtension fExtension; |
| /** The position category defining the projection */ |
| private String fProjectionCategory; |
| /** The document event issued by the parent document */ |
| private DocumentEvent fParentEvent; |
| /** The document event issued and to be issued by the projection document */ |
| private SlaveDocumentEvent fEvent; |
| /** Indicates whether the projection document initiated a parent document update or not */ |
| private boolean fIsUpdating= false; |
| /** The position updater for the positions managing the fragments */ |
| private FragmentUpdater fFragmentUpdater= new FragmentUpdater(FRAGMENT_CATEGORY); |
| |
| /** |
| * Creates a projection document for the given parent document. |
| * |
| * @param parentDocument the parent Document |
| * @param projectionCategory the document position category whose positions define the projection of the parent document |
| */ |
| public ProjectionDocument(IDocument parentDocument, String projectionCategory) { |
| super(); |
| |
| fParentDocument= parentDocument; |
| if (fParentDocument instanceof IDocumentExtension) |
| fExtension= (IDocumentExtension) fParentDocument; |
| |
| ITextStore s= new ProjectionTextStore(this); |
| ILineTracker tracker= new DefaultLineTracker(); |
| |
| setTextStore(s); |
| setLineTracker(tracker); |
| |
| completeInitialization(); |
| |
| initializeProjection(projectionCategory); |
| tracker.set(s.get(0, s.getLength())); |
| } |
| |
| /** |
| * Initializes the projection document from the parent document based on the given projection category. |
| * |
| * @param projectionCategory the document position category whose positions define the projection of the parent document |
| */ |
| private void initializeProjection(String projectionCategory) { |
| |
| fProjectionCategory= projectionCategory; |
| |
| try { |
| |
| addPositionCategory(FRAGMENT_CATEGORY); |
| addPositionUpdater(fFragmentUpdater); |
| |
| int offset= 0; |
| Position[] patch= fParentDocument.getPositions(fProjectionCategory); |
| for (int i= 0; i < patch.length; i++) { |
| Position p= patch[i]; |
| addPosition(FRAGMENT_CATEGORY, new Fragment(offset, p.length, p)); |
| offset += p.length; |
| } |
| |
| } catch (BadPositionCategoryException x) { |
| } catch (BadLocationException x) { |
| } |
| } |
| |
| /** |
| * Creates a fragment from a postion of the parent document. |
| * |
| * @param parentPosition a position of the parent document |
| * @return the fragment representing the range given by the parent position |
| */ |
| public Fragment createFragment(Position parentPosition) { |
| try { |
| |
| int index= fParentDocument.computeIndexInCategory(fProjectionCategory, parentPosition.offset); |
| if (index <= 0) |
| return new Fragment(0, parentPosition.length, parentPosition); |
| |
| Position[] fragments= getPositions(FRAGMENT_CATEGORY); |
| Position p= fragments[index -1]; |
| return new Fragment(p.offset + p.length, parentPosition.length, parentPosition); |
| |
| } catch (BadPositionCategoryException e) { |
| } catch (BadLocationException e) { |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Returns the index of the position of the given category of the given document that includes the |
| * given offset. <code>direction</code> indicates the direction into which the algorithm should search. |
| * |
| * @param document the document |
| * @param category the position category of <code>document</code> |
| * @param offset the offset into <code>document</code> |
| * @param direction the search direction |
| * @return the index of the position |
| * @throws BadPositionCategoryException if <code>category</code> is not valid in <code>document</code> |
| * @throws BadLocationException if <code>offset</code> is not valid in <code>document</code> |
| */ |
| private int getPositionOfOffset(IDocument document, String category, int offset, int direction ) throws BadPositionCategoryException, BadLocationException{ |
| |
| Position[] positions= document.getPositions(category); |
| if (positions != null && positions.length > 0) { |
| |
| // test for inclusion |
| int index= document.computeIndexInCategory(category, offset); |
| if (index < positions.length && positions[index].includes(offset)) |
| return index; |
| if (index > 0 && positions[index -1].includes(offset)) |
| return index -1; |
| |
| // find next accorrding to direction |
| if (direction != 0) { |
| if (direction > 0) { |
| if (index < positions.length && positions[index].overlapsWith(offset, direction)) |
| return index; |
| } else { |
| if (index > 0 && positions[index -1].overlapsWith(offset + direction, -direction)) |
| return index -1; |
| } |
| } |
| } |
| |
| return -1; |
| } |
| |
| /** |
| * Returns the position which is used to manage a parent |
| * document range represented in this projection document and that |
| * includes or is close to the given parent document offset. The distance |
| * is computed based on the given direction hint. |
| * |
| * @param offsetInParent the parent document offset |
| * @param direction the direction hint used for computing the distance |
| * @return position the parent document position including or near to the parent document offset |
| */ |
| private Position getParentDocumentPositionOfOffset(int offsetInParent, int direction ) { |
| try { |
| |
| int index= getPositionOfOffset(fParentDocument, fProjectionCategory, offsetInParent, direction); |
| if (index > -1) { |
| Position[] positions= fParentDocument.getPositions(fProjectionCategory); |
| return positions[index]; |
| } |
| |
| } catch (BadPositionCategoryException x) { |
| } catch (BadLocationException x) { |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Returns the offset in the projection document corresponding to the |
| * given parent document offset. |
| * |
| * @param offsetInParent the parent document offset |
| * @return the projection document offset corresponding to the given parent document offset |
| */ |
| private int toProjectionDocumentOffset(int offsetInParent, int direction) { |
| |
| Position p= getParentDocumentPositionOfOffset(offsetInParent, direction); |
| if (p == null) |
| return -1; |
| |
| int relative= offsetInParent - p.offset; |
| |
| if (direction > 0) { |
| if (relative < 0) |
| relative= 0; |
| } else if (direction < 0) { |
| if (relative >= p.length) |
| relative= p.length -1; |
| } |
| |
| Fragment f= findCorrespondingFragment(p); |
| return f.offset + relative; |
| } |
| |
| /** |
| * Creates a position describing the projection document range corresponding to |
| * the given parent document range. |
| * |
| * @param offsetInParent the parent document offset |
| * @param lengthInParent the parent document lengh |
| * @return position describing the projection document range corresponding to the given parent document range |
| */ |
| public Position computeProjectionDocumentPosition(int offsetInParent, int lengthInParent) { |
| |
| Position p= getParentDocumentCoverage(); |
| if (p != null) { |
| |
| if (p.overlapsWith(offsetInParent, lengthInParent)) { |
| |
| int o1= toProjectionDocumentOffset(offsetInParent, lengthInParent); |
| if (o1 == -1) |
| return null; |
| |
| if (lengthInParent == 0) |
| return new Position(o1, 0); |
| |
| int o2= toProjectionDocumentOffset(offsetInParent + lengthInParent -1, 1 - lengthInParent); |
| if (o2 == -1) |
| return null; |
| |
| return new Position(o1, o2 - o1 + 1); |
| |
| } else if (p.getOffset() + p.getLength() == offsetInParent + lengthInParent) { |
| |
| Position[] fragments= getFragmentation(); |
| if (fragments != null && fragments.length > 0) { |
| Position last= fragments[fragments.length -1]; |
| return new Position(last.getOffset() + last.getLength()); |
| } |
| } |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Returns the offset in the parent document that corresponds to the given offset in this |
| * projection document. |
| * |
| * @param offset the offset in the projection document |
| * @return the corresponding parent document offset |
| * @throws BadLocationException if <code>offset</code> is not valid in this projection document |
| */ |
| public int toParentDocumentOffset(int offset) throws BadLocationException { |
| Fragment fragment= getFragmentOfOffset(offset); |
| |
| if (fragment == null) { |
| |
| // if (offset == 0) |
| // return 0; |
| // throw new BadLocationException(); |
| |
| Position[] fragmentation= getFragmentation(); |
| if (fragmentation != null && fragmentation.length > 0) { |
| Fragment last= (Fragment) fragmentation[fragmentation.length -1]; |
| if (last.offset + last.length == offset) { |
| Position origin= last.getOrigin(); |
| return origin.offset + origin.length; |
| } |
| } |
| |
| throw new BadLocationException(); |
| } |
| |
| int relative= offset - fragment.offset; |
| return fragment.getOrigin().offset + relative; |
| } |
| |
| /** |
| * Computes and returns the region of the parent document that corresponds to the given region of the |
| * projection document. |
| * |
| * @param offset the offset of the projection document region |
| * @param length the length of the projection document region |
| * @return the corresponding region of the parent document |
| * @throws BadLocationException if the given projection document region is not valid |
| */ |
| public IRegion computeParentDocumentRegion(int offset, int length) throws BadLocationException { |
| |
| if (length == 0) { |
| if (offset == 0 && length == getLength()) |
| return new Region(0, fParentDocument.getLength()); |
| return new Region(toParentDocumentOffset(offset), 0); |
| } |
| |
| int o1= toParentDocumentOffset(offset); |
| int o2= toParentDocumentOffset(offset + length -1); |
| return new Region(o1, o2 - o1 + 1); |
| } |
| |
| /** |
| * Removes all fragments and thereby clears this projection document. |
| */ |
| public void removeAllFragments() { |
| Position[] projection= getProjection(); |
| if (projection == null) |
| return; |
| |
| for (int i= 0; i < projection.length; i++) { |
| try { |
| removeFragment(projection[i]); |
| } catch (BadLocationException e) { |
| } |
| } |
| } |
| |
| /** |
| * Add a new fragment of the parent document to this projection document. |
| * |
| * @param offsetInParent offset of the parent document range |
| * @param lengthInParent length of the parent document range |
| * @return returns the position representing the parent document range in this projection document |
| * @throws BadLocationException |
| */ |
| public void addFragment(int offsetInParent, int lengthInParent) throws BadLocationException { |
| |
| if (lengthInParent == 0) |
| return; |
| |
| try { |
| |
| ProjectionPosition p= new ProjectionPosition(this, offsetInParent, lengthInParent); |
| fParentDocument.addPosition(fProjectionCategory, p); |
| |
| Fragment fragment= createFragment(p); |
| p.setFragment(fragment); |
| fireDocumentProjectionChanged(new DocumentEvent(this, fragment.offset, 0, fParentDocument.get(offsetInParent, lengthInParent))); |
| addPosition(FRAGMENT_CATEGORY, fragment); |
| |
| |
| getTracker().set(getStore().get(0, getStore().getLength())); |
| |
| } catch (BadPositionCategoryException x) { |
| } |
| |
| } |
| |
| /** |
| * Joins all fragments that represent neighboring regions in the parent document. |
| */ |
| public void joinFragments() { |
| try { |
| while (joinTwoFragments()) {} |
| } catch (BadPositionCategoryException x) { |
| } |
| } |
| |
| /** |
| * Joins the first two fragments that represent neighboring regions of the parent document. |
| * @return <code>true</code> if two segments have been joined, <code>false</code> otherwise |
| * @throws BadPositionCategoryException |
| */ |
| private boolean joinTwoFragments() throws BadPositionCategoryException { |
| Position[] projection= getProjection(); |
| if (projection != null && projection.length > 0) { |
| Position previous= projection[0]; |
| for (int i= 1; i < projection.length; i++) { |
| Position current= projection[i]; |
| if (previous.offset + previous.length == current.offset) { |
| join(previous, current); |
| return true; |
| } |
| previous= current; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Joins the fragments of this projection document that correspond to the two given, |
| * neighboring ranges of the parent document. |
| * |
| * @param p1 lower range in the parent document |
| * @param p2 higher range of the parent document |
| * @throws BadPositionCategoryException if the fragment position category is not defined in this projection document |
| */ |
| private void join(Position p1, Position p2) throws BadPositionCategoryException { |
| // remove p2 |
| Fragment fragment= findCorrespondingFragment(p2); |
| removePosition(FRAGMENT_CATEGORY, fragment); |
| fParentDocument.removePosition(fProjectionCategory, p2); |
| // extend p1 by length of p2 |
| fragment= findCorrespondingFragment(p1); |
| fragment.length += p2.length; |
| p1.length += p2.length; |
| } |
| |
| /** |
| * Removes the fragment that corresponds to the given parent document range. |
| * |
| * @param parentPosition the position representing the parent document range |
| * @throws BadLocationException if the fragment position category is not defined in this projection document |
| */ |
| public void removeFragment(Position parentPosition) throws BadLocationException { |
| try { |
| |
| Fragment fragment= findCorrespondingFragment(parentPosition); |
| if (fragment != null) { |
| removePosition(FRAGMENT_CATEGORY, fragment); |
| fParentDocument.removePosition(fProjectionCategory, parentPosition); |
| fireDocumentProjectionChanged(new DocumentEvent(this, fragment.offset, fragment.length, null)); |
| getTracker().set(getStore().get(0, getStore().getLength())); |
| } |
| |
| } catch (BadPositionCategoryException x) { |
| } |
| } |
| |
| /** |
| * Returns the list of fragments whose corresponding ranges in the parent document overlap with |
| * the specifed range of the parent document. |
| * |
| * @param offsetInParent the offset of the parent document range |
| * @param lengthInParent the length of the parent document range |
| * @return the list of affected fragments |
| */ |
| public Position[] getAffectedFragments(int offsetInParent, int lengthInParent) { |
| |
| Position p= computeProjectionDocumentPosition(offsetInParent, lengthInParent); |
| if (p == null) |
| return null; |
| |
| Fragment[] f= getFragmentsOfRange(p.offset, p.length); |
| if (f == null) |
| return null; |
| |
| Position[] result= new Position[f.length]; |
| for (int i= 0; i < f.length; i++) |
| result[i]= f[i].getOrigin(); |
| return result; |
| } |
| |
| /** |
| * Finds the fragment that represents the given parent document range in this projection document. |
| * |
| * @param parentPosition the parent document range |
| * @return the fragment representing the given parent document range |
| */ |
| private Fragment findCorrespondingFragment(Position parentPosition) { |
| try { |
| Position[] fragments= getPositions(FRAGMENT_CATEGORY); |
| for (int i= 0; i < fragments.length; i++) { |
| Fragment f= (Fragment) fragments[i]; |
| if (parentPosition.equals(f.getOrigin())) |
| return f; |
| } |
| } catch (BadPositionCategoryException x) { |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Returns the fragment that contains the given offset. |
| * |
| * @param offset the offset |
| * @return the fragment that contains the given offset |
| * @throws BadLocationException if <code>offset</code> is not a valid offset |
| */ |
| protected Fragment getFragmentOfOffset(int offset) throws BadLocationException { |
| try { |
| int index= getPositionOfOffset(this, FRAGMENT_CATEGORY, offset, 0); |
| if (index > -1) { |
| Position[] fragments= getPositions(FRAGMENT_CATEGORY); |
| return (Fragment) fragments[index]; |
| } |
| } catch (BadPositionCategoryException x) { |
| } |
| return null; |
| } |
| |
| /** |
| * Returns the minimal consecutive list of fragments that completely covers the given range. |
| * |
| * @param offset the offset of the range |
| * @param length the length of the range |
| * @return the minimal consecutive list of fragments convering the given range |
| */ |
| protected Fragment[] getFragmentsOfRange(int offset, int length) { |
| |
| try { |
| |
| int start= getPositionOfOffset(this, FRAGMENT_CATEGORY, offset, length); |
| int end= getPositionOfOffset(this, FRAGMENT_CATEGORY, offset + length -1, 1 - length); |
| |
| if (start > -1 && end > -1) { |
| |
| Position[] positions= getPositions(FRAGMENT_CATEGORY); |
| |
| if (start == end) |
| return new Fragment[] { (Fragment) positions[start] }; |
| |
| Fragment[] result= new Fragment[end - start + 1]; |
| for (int i= start; i <= end; i++) |
| result[i - start]= (Fragment) positions[i]; |
| sortFragments(result); |
| return result; |
| } |
| |
| } catch (BadPositionCategoryException e) { |
| } catch (BadLocationException e) { |
| } |
| |
| return new Fragment[0]; |
| } |
| |
| /** |
| * Sorts a list of fragments based on the offsets of their corresponding ranges in the parent document. |
| * |
| * @param result the list for fragments |
| */ |
| private void sortFragments(Object[] result) { |
| |
| Comparator comparator= new Comparator() { |
| |
| public int compare(Object o1, Object o2) { |
| Fragment f1= (Fragment) o1; |
| Fragment f2= (Fragment) o2; |
| return f1.getOrigin().getOffset() - f2.getOrigin().getOffset(); |
| } |
| |
| public boolean equals(Object obj) { |
| return false; |
| } |
| }; |
| |
| Arrays.sort(result, comparator); |
| } |
| |
| /** |
| * Returns the minimal range of the parent document that covers all ranges that |
| * correspond to the fragments of this projection document. |
| * |
| * @return a position describing the minimal parent document range covering all fragments |
| */ |
| public Position getParentDocumentCoverage() { |
| Position[] projection= getProjection(); |
| if (projection != null && projection.length > 0) { |
| Position first=projection[0]; |
| Position last= projection[projection.length -1]; |
| return new Position(first.offset, last.offset - first.offset + last.length); |
| } |
| return new Position(0, 0); |
| } |
| |
| /** |
| * The projection of the parent document has been changed by inserting or removing |
| * new fragments into this projection document. The projection change is described in |
| * the given <code>DocumentEvent</code>. All positions managed by this projection |
| * document must be adapted accordingly. |
| * |
| * @param event the document event |
| */ |
| private void fireDocumentProjectionChanged(DocumentEvent event) { |
| fFragmentUpdater.enableShiftMode(true); |
| try { |
| updatePositions(event); |
| } finally { |
| fFragmentUpdater.enableShiftMode(false); |
| } |
| } |
| |
| /** |
| * Returns parent document. |
| * |
| * @return the parent document |
| */ |
| public IDocument getParentDocument() { |
| return fParentDocument; |
| } |
| |
| /** |
| * Returns the ranges of the parent document that correspond to the fragments of this |
| * projection document. |
| * |
| * @return the ranges of the parent document corresponding to the fragments |
| */ |
| public Position[] getProjection() { |
| try { |
| return fParentDocument.getPositions(fProjectionCategory); |
| } catch (BadPositionCategoryException x) { |
| } |
| return null; |
| } |
| |
| /** |
| * Returns the list of all fragments of this projection document. |
| * |
| * @return the list of all fragments of this projection document |
| */ |
| public Position[] getFragmentation() { |
| try { |
| |
| Position[] fragmentation= getPositions(FRAGMENT_CATEGORY); |
| sortFragments(fragmentation); |
| return fragmentation; |
| |
| } catch (BadPositionCategoryException x) { |
| } |
| return null; |
| } |
| |
| /** |
| * Transforms a document event of the parent document into a projection document |
| * based document event. |
| * |
| * @param e the parent document event |
| * @return the slave document event |
| */ |
| private SlaveDocumentEvent normalize(DocumentEvent e) { |
| |
| Position c= computeProjectionDocumentPosition(e.getOffset(), e.getLength()); |
| |
| if (c != null) { |
| if (c.length == 0) { |
| int insertLength= e.getText() == null ? 0 : e.getText().length(); |
| if (insertLength == 0) |
| return null; |
| } |
| return new SlaveDocumentEvent(this, c.offset, c.length, e.getText(), e); |
| } |
| |
| return null; |
| } |
| |
| /** |
| * When called, this projection document is informed about a forthcoming change |
| * of its parent document. This projection document checks whether the parent |
| * document change affects it and if so informs all document listeners. |
| * |
| * @param event the parent document event |
| */ |
| public void parentDocumentAboutToBeChanged(DocumentEvent event) { |
| fParentEvent= event; |
| fEvent= normalize(event); |
| if (fEvent != null) |
| delayedFireDocumentAboutToBeChanged(); |
| } |
| |
| /** |
| * When called, this projection document is informed about a change of its parent document. |
| * If this projection document is affected it informs all of its document listeners. |
| * |
| * @param event the parent document event |
| */ |
| public void parentDocumentChanged(DocumentEvent event) { |
| if ( !fIsUpdating && event == fParentEvent && fEvent != null) { |
| try { |
| getTracker().replace(fEvent.getOffset(), fEvent.getLength(), fEvent.getText()); |
| fireDocumentChanged(fEvent); |
| } catch (BadLocationException x) { |
| Assert.isLegal(false); |
| } |
| } |
| } |
| |
| /* |
| * @see AbstractDocument#fireDocumentAboutToBeChanged(DocumentEvent) |
| */ |
| protected void fireDocumentAboutToBeChanged(DocumentEvent event) { |
| // delay it until there is a notification from the parent document |
| // otherwise there it is expensive to construct the parent document information |
| } |
| |
| /** |
| * Fires the slave document event as about-to-be-changed event to all registed listeners. |
| */ |
| private void delayedFireDocumentAboutToBeChanged() { |
| super.fireDocumentAboutToBeChanged(fEvent); |
| } |
| |
| /** |
| * 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(fEvent); |
| } |
| |
| /* |
| * @see IDocument#replace(int, int, String) |
| */ |
| public void replace(int offset, int length, String text) throws BadLocationException { |
| try { |
| fIsUpdating= true; |
| if (fExtension != null) |
| fExtension.stopPostNotificationProcessing(); |
| |
| super.replace(offset, length, text); |
| |
| } finally { |
| fIsUpdating= false; |
| if (fExtension != null) |
| fExtension.resumePostNotificationProcessing(); |
| } |
| } |
| |
| /* |
| * @see IDocument#set(String) |
| */ |
| public void set(String text) { |
| try { |
| fIsUpdating= true; |
| if (fExtension != null) |
| fExtension.stopPostNotificationProcessing(); |
| |
| super.set(text); |
| |
| } finally { |
| fIsUpdating= false; |
| if (fExtension != null) |
| fExtension.resumePostNotificationProcessing(); |
| } |
| } |
| |
| /* |
| * @see IDocumentExtension#registerPostNotificationReplace(IDocumentListener, IDocumentExtension.IReplace) |
| */ |
| public void registerPostNotificationReplace(IDocumentListener owner, IDocumentExtension.IReplace replace) { |
| if (!fIsUpdating) |
| throw new UnsupportedOperationException(); |
| super.registerPostNotificationReplace(owner, replace); |
| } |
| |
| |
| /** |
| * Convenience method for removing and adapting the fragments whose corresponding |
| * ranges in the parent document are included or overlap with the given range of the |
| * parent document. |
| * |
| * @param offsetInParent the offset of the parent document range |
| * @param lengthInParent the length of the parent document range |
| */ |
| public void hide(int offsetInParent, int lengthInParent) { |
| |
| IDocument parent= getParentDocument(); |
| Position[] effected= getAffectedFragments(offsetInParent, lengthInParent); |
| |
| try { |
| |
| if (effected == null) { |
| // populate new document with two new fragments, the left and the right of the hidden region |
| int end= offsetInParent + lengthInParent; |
| addFragment(0, offsetInParent); |
| addFragment(end, parent.getLength() - end); |
| } else if (effected.length == 1) { |
| // the only affected fragment must be splitted into two |
| Position fragment= effected[0]; |
| removeFragment(fragment); |
| addFragment(fragment.offset, offsetInParent - fragment.offset); |
| int secondOffset= offsetInParent + lengthInParent; |
| addFragment(secondOffset, fragment.offset + fragment.length - secondOffset); |
| } else { |
| // first expand and than collapse |
| internalShow(offsetInParent, lengthInParent, effected); |
| hide(offsetInParent, lengthInParent); |
| } |
| |
| joinFragments(); |
| |
| } catch (BadLocationException x) { |
| } |
| } |
| |
| /** |
| * Convenience method for adding fragments or adapting existing fragments so that their corresponding |
| * ranges in the parent document include the given range of the parent document. |
| * |
| * @param offsetInParent the offset of the parent document range |
| * @param lengthInParent the length of the parent document range |
| */ |
| public void show(int offsetInParent, int lengthInParent) { |
| |
| Position[] effected= getAffectedFragments(offsetInParent, lengthInParent); |
| if (effected == null || effected.length == 0) { |
| try { |
| addFragment(offsetInParent, lengthInParent); |
| joinFragments(); |
| } catch (BadLocationException x) { |
| } |
| return; |
| } |
| |
| internalShow(offsetInParent, lengthInParent, effected); |
| joinFragments(); |
| |
| } |
| |
| /** |
| * Removes the given fragments and inserts a new fragment whose parent document |
| * range corresponds the given range of the parent document. |
| * |
| * @param offsetInParent the offset of the parent document range |
| * @param lengthInParent the length of the parent document range |
| * @param effected the list for fragments to be removed |
| */ |
| private void internalShow(int offsetInParent, int lengthInParent, Position[] effected) { |
| try { |
| |
| int size= effected.length; |
| for (int i= 0; i < size; i++) |
| removeFragment(effected[i]); |
| |
| int offset= Math.min(offsetInParent, effected[0].offset); |
| int end= Math.max(offsetInParent + lengthInParent, effected[size -1].offset + effected[size -1].length); |
| addFragment(offset, end - offset); |
| |
| } catch (BadLocationException x) { |
| } |
| } |
| } |