X-Git-Url: http://secure.phpeclipse.com diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/link/LinkedPositionManager.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/link/LinkedPositionManager.java index 4ce53ee..6f1157d 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/link/LinkedPositionManager.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/link/LinkedPositionManager.java @@ -1,7 +1,14 @@ -/* - * (c) Copyright IBM Corp. 2000, 2001. - * All Rights Reserved. - */ +/******************************************************************************* + * 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 net.sourceforge.phpdt.internal.ui.text.link; import java.util.Arrays; @@ -10,69 +17,81 @@ import java.util.HashMap; import java.util.Map; import net.sourceforge.phpeclipse.PHPeclipsePlugin; + +//incastrix +//import org.eclipse.jface.text.Assert; +import org.eclipse.core.runtime.Assert; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.BadPositionCategoryException; +import org.eclipse.jface.text.DocumentCommand; import org.eclipse.jface.text.DocumentEvent; +import org.eclipse.jface.text.IAutoEditStrategy; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IDocumentExtension; import org.eclipse.jface.text.IDocumentListener; import org.eclipse.jface.text.IPositionUpdater; import org.eclipse.jface.text.Position; import org.eclipse.jface.text.TypedPosition; -import org.eclipse.jface.util.Assert; - -//import org.eclipse.jdt.internal.ui.JavaPlugin; +//import org.eclipse.jface.text.contentassist.ICompletionProposal; /** - * This class manages linked positions in a document. Positions are linked - * by type names. If positions have the same type name, they are considered - * as linked. + * This class manages linked positions in a document. Positions are linked by + * type names. If positions have the same type name, they are considered as + * linked. * * The manager remains active on a document until any of the following actions * occurs: * * */ -public class LinkedPositionManager implements IDocumentListener, IPositionUpdater { - - private static class PositionComparator implements Comparator { - /* - * @see Comparator#compare(Object, Object) - */ - public int compare(Object object0, Object object1) { - Position position0= (Position) object0; - Position position1= (Position) object1; - - return position0.getOffset() - position1.getOffset(); - } - } - +public class LinkedPositionManager implements IDocumentListener, + IPositionUpdater, IAutoEditStrategy { + + // This class still exists to properly handle code assist. + // This is due to the fact that it cannot be distinguished betweeen document + // changes which are + // issued by code assist and document changes which origin from another text + // viewer. + // There is a conflict in interest since in the latter case the linked mode + // should be left, but in the former case + // the linked mode should remain. + // To support content assist, document changes have to be propagated to + // connected positions + // by registering replace commands using IDocumentExtension. + // if it wasn't for the support of content assist, the documentChanged() + // method could be reduced to + // a simple call to leave(true) private class Replace implements IDocumentExtension.IReplace { - + private Position fReplacePosition; + private int fReplaceDeltaOffset; + private int fReplaceLength; + private String fReplaceText; - - public Replace(Position position, int deltaOffset, int length, String text) { - fReplacePosition= position; - fReplaceDeltaOffset= deltaOffset; - fReplaceLength= length; - fReplaceText= text; + + public Replace(Position position, int deltaOffset, int length, + String text) { + fReplacePosition = position; + fReplaceDeltaOffset = deltaOffset; + fReplaceLength = length; + fReplaceText = text; } - + public void perform(IDocument document, IDocumentListener owner) { document.removeDocumentListener(owner); try { - document.replace(fReplacePosition.getOffset() + fReplaceDeltaOffset, fReplaceLength, fReplaceText); + document.replace(fReplacePosition.getOffset() + + fReplaceDeltaOffset, fReplaceLength, fReplaceText); } catch (BadLocationException e) { PHPeclipsePlugin.log(e); // TBD @@ -81,63 +100,140 @@ public class LinkedPositionManager implements IDocumentListener, IPositionUpdate } } - private static final String LINKED_POSITION= "LinkedPositionManager.linked.position"; //$NON-NLS-1$ - private static final Comparator fgPositionComparator= new PositionComparator(); - private static final Map fgActiveManagers= new HashMap(); - + private static class PositionComparator implements Comparator { + /* + * @see Comparator#compare(Object, Object) + */ + public int compare(Object object0, Object object1) { + Position position0 = (Position) object0; + Position position1 = (Position) object1; + + return position0.getOffset() - position1.getOffset(); + } + } + + private static final String LINKED_POSITION_PREFIX = "LinkedPositionManager.linked.position"; //$NON-NLS-1$ + + private static final Comparator fgPositionComparator = new PositionComparator(); + + private static final Map fgActiveManagers = new HashMap(); + + private static int fgCounter = 0; + private IDocument fDocument; - - private LinkedPositionListener fListener; + + private ILinkedPositionListener fListener; + + private String fPositionCategoryName; + + private boolean fMustLeave; + + /** + * Flag that records the state of this manager. As there are many different + * entities that may call leave or exit, these cannot always be sure whether + * the linked position infrastructure is still active. This is especially + * true for multithreaded situations. + */ + private boolean fIsActive = false; /** - * Creates a LinkedPositionManager for a IDocument. + * Creates a LinkedPositionManager for a + * IDocument. * - * @param document the document to use with linked positions. + * @param document + * the document to use with linked positions. + * @param canCoexist + * true if this manager can coexist with an + * already existing one */ - public LinkedPositionManager(IDocument document) { + public LinkedPositionManager(IDocument document, boolean canCoexist) { Assert.isNotNull(document); - - fDocument= document; - install(); + fDocument = document; + fPositionCategoryName = LINKED_POSITION_PREFIX + (fgCounter++); + install(canCoexist); + } + + /** + * Creates a LinkedPositionManager for a + * IDocument. + * + * @param document + * the document to use with linked positions. + */ + public LinkedPositionManager(IDocument document) { + this(document, false); } /** * Sets a listener to notify changes of current linked position. */ - public void setLinkedPositionListener(LinkedPositionListener listener) { - fListener= listener; + public void setLinkedPositionListener(ILinkedPositionListener listener) { + fListener = listener; } - + /** - * Adds a linked position to the manager. - * There are the following constraints for linked positions: + * Adds a linked position to the manager with the type being the content of + * the document at the specified range. There are the following constraints + * for linked positions: * * * - * @param offset the offset of the position. - * @param length the length of the position. + * @param offset + * the offset of the position. + * @param length + * the length of the position. */ public void addPosition(int offset, int length) throws BadLocationException { - Position[] positions= getPositions(fDocument); + String type = fDocument.get(offset, length); + addPosition(offset, length, type); + } + + /** + * Adds a linked position of the specified position type to the manager. + * There are the following constraints for linked positions: + * + * + * + * @param offset + * the offset of the position. + * @param length + * the length of the position. + * @param type + * the position type name - any positions with the same type are + * linked. + */ + public void addPosition(int offset, int length, String type) + throws BadLocationException { + Position[] positions = getPositions(fDocument); if (positions != null) { for (int i = 0; i < positions.length; i++) if (collides(positions[i], offset, length)) - throw new BadLocationException(LinkedPositionMessages.getString(("LinkedPositionManager.error.position.collision"))); //$NON-NLS-1$ + throw new BadLocationException( + LinkedPositionMessages + .getString(("LinkedPositionManager.error.position.collision"))); //$NON-NLS-1$ } - - String type= fDocument.get(offset, length); - if (containsLineDelimiters(type)) - throw new BadLocationException(LinkedPositionMessages.getString(("LinkedPositionManager.error.contains.line.delimiters"))); //$NON-NLS-1$ + String content = fDocument.get(offset, length); + + if (containsLineDelimiters(content)) + throw new BadLocationException( + LinkedPositionMessages + .getString(("LinkedPositionManager.error.contains.line.delimiters"))); //$NON-NLS-1$ try { - fDocument.addPosition(LINKED_POSITION, new TypedPosition(offset, length, type)); + fDocument.addPosition(fPositionCategoryName, new TypedPosition( + offset, length, type)); } catch (BadPositionCategoryException e) { PHPeclipsePlugin.log(e); Assert.isTrue(false); @@ -145,55 +241,198 @@ public class LinkedPositionManager implements IDocumentListener, IPositionUpdate } /** + * Adds a linked position to the manager. The current document content at + * the specified range is taken as the position type. + *

+ * There are the following constraints for linked positions: + * + *

+ * + * It is usually best to set the first item in + * additionalChoices to be equal with the text inserted at + * the current position. + *

+ * + * @param offset + * the offset of the position. + * @param length + * the length of the position. + * @param additionalChoices + * a number of additional choices to be displayed when selecting + * a position of this type. + */ +// public void addPosition(int offset, int length, +// ICompletionProposal[] additionalChoices) +// throws BadLocationException { +// String type = fDocument.get(offset, length); +// addPosition(offset, length, type, additionalChoices); +// } + + /** + * Adds a linked position of the specified position type to the manager. + * There are the following constraints for linked positions: + * + * + * + * It is usually best to set the first item in + * additionalChoices to be equal with the text inserted at + * the current position. + * + * @param offset + * the offset of the position. + * @param length + * the length of the position. + * @param type + * the position type name - any positions with the same type are + * linked. + * @param additionalChoices + * a number of additional choices to be displayed when selecting + * a position of this type. + */ +// public void addPosition(int offset, int length, String type, +// ICompletionProposal[] additionalChoices) +// throws BadLocationException { +// Position[] positions = getPositions(fDocument); +// +// if (positions != null) { +// for (int i = 0; i < positions.length; i++) +// if (collides(positions[i], offset, length)) +// throw new BadLocationException( +// LinkedPositionMessages +// .getString(("LinkedPositionManager.error.position.collision"))); //$NON-NLS-1$ +// } +// +// String content = fDocument.get(offset, length); +// +// if (containsLineDelimiters(content)) +// throw new BadLocationException( +// LinkedPositionMessages +// .getString(("LinkedPositionManager.error.contains.line.delimiters"))); //$NON-NLS-1$ +// +// try { +// fDocument.addPosition(fPositionCategoryName, new ProposalPosition( +// offset, length, type, additionalChoices)); +// } catch (BadPositionCategoryException e) { +// PHPeclipsePlugin.log(e); +// Assert.isTrue(false); +// } +// } + + /** * Tests if a manager is already active for a document. */ - public static boolean hasActiveManager(IDocument document) { - return fgActiveManagers.get(document) != null; - } +// public static boolean hasActiveManager(IDocument document) { +// return fgActiveManagers.get(document) != null; +// } + + private void install(boolean canCoexist) { + + if (fIsActive) + ;// JavaPlugin.log(new Status(IStatus.WARNING, + // JavaPlugin.getPluginId(), IStatus.OK, "LinkedPositionManager + // is already active: "+fPositionCategoryName, new + // IllegalStateException())); //$NON-NLS-1$ + else { + fIsActive = true; + // JavaPlugin.log(new Status(IStatus.INFO, JavaPlugin.getPluginId(), + // IStatus.OK, "LinkedPositionManager activated: + // "+fPositionCategoryName, new Exception())); //$NON-NLS-1$ + } - private void install() { - LinkedPositionManager manager= (LinkedPositionManager) fgActiveManagers.get(fDocument); - if (manager != null) - manager.leave(true); + if (!canCoexist) { + LinkedPositionManager manager = (LinkedPositionManager) fgActiveManagers + .get(fDocument); + if (manager != null) + manager.leave(true); + } fgActiveManagers.put(fDocument, this); - - fDocument.addPositionCategory(LINKED_POSITION); - fDocument.addPositionUpdater(this); + fDocument.addPositionCategory(fPositionCategoryName); + fDocument.addPositionUpdater(this); fDocument.addDocumentListener(this); - } - + + fMustLeave = false; + } + /** - * Leaves the linked mode. If unsuccessful, the linked positions - * are restored to the values at the time they were added. + * Leaves the linked mode. If unsuccessful, the linked positions are + * restored to the values at the time they were added. */ - public void uninstall(boolean success) { - fDocument.removeDocumentListener(this); + public void uninstall(boolean success) { - try { - Position[] positions= getPositions(fDocument); - if ((!success) && (positions != null)) { - // restore - for (int i= 0; i != positions.length; i++) { - TypedPosition position= (TypedPosition) positions[i]; - fDocument.replace(position.getOffset(), position.getLength(), position.getType()); + if (!fIsActive) + // we migth also just return + ;// JavaPlugin(new Status(IStatus.WARNING, + // JavaPlugin.getPluginId(), IStatus.OK, "LinkedPositionManager + // activated: "+fPositionCategoryName, new + // IllegalStateException())); //$NON-NLS-1$ + else { + fDocument.removeDocumentListener(this); + + try { + Position[] positions = getPositions(fDocument); + if ((!success) && (positions != null)) { + // restore + for (int i = 0; i != positions.length; i++) { + TypedPosition position = (TypedPosition) positions[i]; + fDocument.replace(position.getOffset(), position + .getLength(), position.getType()); + } } - } - - fDocument.removePositionCategory(LINKED_POSITION); - } catch (BadLocationException e) { - PHPeclipsePlugin.log(e); - Assert.isTrue(false); + fDocument.removePositionCategory(fPositionCategoryName); - } catch (BadPositionCategoryException e) { - PHPeclipsePlugin.log(e); - Assert.isTrue(false); + fIsActive = false; + // JavaPlugin.log(new Status(IStatus.INFO, + // JavaPlugin.getPluginId(), IStatus.OK, "LinkedPositionManager + // deactivated: "+fPositionCategoryName, new Exception())); + // //$NON-NLS-1$ - } finally { - fDocument.removePositionUpdater(this); - fgActiveManagers.remove(fDocument); + } catch (BadLocationException e) { + PHPeclipsePlugin.log(e); + Assert.isTrue(false); + + } catch (BadPositionCategoryException e) { + PHPeclipsePlugin.log(e); + Assert.isTrue(false); + + } finally { + fDocument.removePositionUpdater(this); + fgActiveManagers.remove(fDocument); + } } + + } + + /** + * Returns the position at the given offset, null if there is + * no position. + * + * @since 2.1 + */ + public Position getPosition(int offset) { + Position[] positions = getPositions(fDocument); + if (positions == null) + return null; + + for (int i = positions.length - 1; i >= 0; i--) { + Position position = positions[i]; + if (offset >= position.getOffset() + && offset <= position.getOffset() + position.getLength()) + return positions[i]; + } + + return null; } /** @@ -205,60 +444,91 @@ public class LinkedPositionManager implements IDocumentListener, IPositionUpdate return getNextPosition(-1); } + public Position getLastPosition() { + Position[] positions = getPositions(fDocument); + for (int i = positions.length - 1; i >= 0; i--) { + String type = ((TypedPosition) positions[i]).getType(); + int j; + for (j = 0; j != i; j++) + if (((TypedPosition) positions[j]).getType().equals(type)) + break; + + if (j == i) + return positions[i]; + } + + return null; + } + /** - * Returns the next linked position with an offset greater than offset. - * If another position with the same type and offset lower than offset - * exists, the position is skipped. + * Returns the next linked position with an offset greater than + * offset. If another position with the same type and offset + * lower than offset exists, the position is skipped. * * @return returns null if no linked position exist. */ public Position getNextPosition(int offset) { - Position[] positions= getPositions(fDocument); + Position[] positions = getPositions(fDocument); return findNextPosition(positions, offset); } private static Position findNextPosition(Position[] positions, int offset) { // skip already visited types - for (int i= 0; i != positions.length; i++) { + for (int i = 0; i != positions.length; i++) { if (positions[i].getOffset() > offset) { - String type= ((TypedPosition) positions[i]).getType(); + String type = ((TypedPosition) positions[i]).getType(); int j; for (j = 0; j != i; j++) if (((TypedPosition) positions[j]).getType().equals(type)) break; if (j == i) - return positions[i]; + return positions[i]; } } return null; } - + /** - * Returns the position with the greatest offset smaller than offset. - * + * Returns the position with the greatest offset smaller than + * offset. + * * @return returns null if no linked position exist. */ public Position getPreviousPosition(int offset) { - Position[] positions= getPositions(fDocument); + Position[] positions = getPositions(fDocument); if (positions == null) return null; - Position lastPosition= null; - Position position= getFirstPosition(); - - while ((position != null) && (position.getOffset() < offset)) { - lastPosition= position; - position= findNextPosition(positions, position.getOffset()); - } - + TypedPosition currentPosition = (TypedPosition) findCurrentPosition( + positions, offset); + String currentType = currentPosition == null ? null : currentPosition + .getType(); + + Position lastPosition = null; + Position position = getFirstPosition(); + + while (position != null && position.getOffset() < offset) { + if (!((TypedPosition) position).getType().equals(currentType)) + lastPosition = position; + position = findNextPosition(positions, position.getOffset()); + } + return lastPosition; } - private static Position[] getPositions(IDocument document) { + private Position[] getPositions(IDocument document) { + + if (!fIsActive) + // we migth also just return an empty array + ;// JavaPlugin(new Status(IStatus.WARNING, + // JavaPlugin.getPluginId(), IStatus.OK, "LinkedPositionManager + // is not active: "+fPositionCategoryName, new + // IllegalStateException())); //$NON-NLS-1$ + try { - Position[] positions= document.getPositions(LINKED_POSITION); + Position[] positions = document.getPositions(fPositionCategoryName); Arrays.sort(positions, fgPositionComparator); return positions; @@ -266,74 +536,86 @@ public class LinkedPositionManager implements IDocumentListener, IPositionUpdate PHPeclipsePlugin.log(e); Assert.isTrue(false); } - + return null; - } + } public static boolean includes(Position position, int offset, int length) { - return - (offset >= position.getOffset()) && - (offset + length <= position.getOffset() + position.getLength()); + return (offset >= position.getOffset()) + && (offset + length <= position.getOffset() + + position.getLength()); } - public static boolean excludes(Position position, int offset, int length) { - return - (offset + length <= position.getOffset()) || - (position.getOffset() + position.getLength() <= offset); - } +// public static boolean excludes(Position position, int offset, int length) { +// return (offset + length <= position.getOffset()) +// || (position.getOffset() + position.getLength() <= offset); +// } /* * Collides if spacing if positions intersect each other or are adjacent. */ private static boolean collides(Position position, int offset, int length) { - return - (offset <= position.getOffset() + position.getLength()) && - (position.getOffset() <= offset + length); + return (offset <= position.getOffset() + position.getLength()) + && (position.getOffset() <= offset + length); } - + private void leave(boolean success) { - uninstall(success); + try { + uninstall(success); + + if (fListener != null) + fListener.exit((success ? LinkedPositionUI.COMMIT : 0) + | LinkedPositionUI.UPDATE_CARET); + } finally { + fMustLeave = false; + } + } + + private void abort() { + uninstall(true); // don't revert anything if (fListener != null) - fListener.exit(success); + fListener.exit(LinkedPositionUI.COMMIT); // don't let the UI + // restore anything + + // don't set fMustLeave, as we will get re-registered by a document + // event } /* * @see IDocumentListener#documentAboutToBeChanged(DocumentEvent) */ public void documentAboutToBeChanged(DocumentEvent event) { - IDocument document= event.getDocument(); - Position[] positions= getPositions(document); - Position position= findCurrentEditablePosition(positions, event.getOffset()); + if (fMustLeave) { + event.getDocument().removeDocumentListener(this); + return; + } + + IDocument document = event.getDocument(); + + Position[] positions = getPositions(document); + Position position = findCurrentPosition(positions, event.getOffset()); // modification outside editable position if (position == null) { - position= findCurrentPosition(positions, event.getOffset()); - - // modification outside any position - if (position == null) { - // check for destruction of constraints (spacing of at least 1) - if ((event.getText().length() == 0) && - (findCurrentPosition(positions, event.getOffset()) != null) && - (findCurrentPosition(positions, event.getOffset() + event.getLength()) != null)) - { - leave(true); - } - - // modification intersects non-editable position - } else { + // check for destruction of constraints (spacing of at least 1) + if ((event.getText() == null || event.getText().length() == 0) + && (findCurrentPosition(positions, event.getOffset()) != null) + && // will never become true, see condition above + (findCurrentPosition(positions, event.getOffset() + + event.getLength()) != null)) { leave(true); } - // modification intersects editable position + // modification intersects editable position } else { // modificaction inside editable position if (includes(position, event.getOffset(), event.getLength())) { if (containsLineDelimiters(event.getText())) leave(true); - // modificaction exceeds editable position + // modificaction exceeds editable position } else { leave(true); } @@ -343,106 +625,207 @@ public class LinkedPositionManager implements IDocumentListener, IPositionUpdate /* * @see IDocumentListener#documentChanged(DocumentEvent) */ - public void documentChanged(DocumentEvent event) { - IDocument document= event.getDocument(); + public void documentChanged(DocumentEvent event) { - Position[] positions= getPositions(document); - TypedPosition currentPosition= (TypedPosition) findCurrentEditablePosition(positions, event.getOffset()); + // have to handle code assist, so can't just leave the linked mode + // leave(true); + + IDocument document = event.getDocument(); + + Position[] positions = getPositions(document); + TypedPosition currentPosition = (TypedPosition) findCurrentPosition( + positions, event.getOffset()); // ignore document changes (assume it won't invalidate constraints) if (currentPosition == null) return; - - int deltaOffset= event.getOffset() - currentPosition.getOffset(); - if (fListener != null) - fListener.setCurrentPosition(currentPosition, deltaOffset + event.getText().length()); - - for (int i= 0; i != positions.length; i++) { - TypedPosition p= (TypedPosition) positions[i]; - - if (p.getType().equals(currentPosition.getType()) && !p.equals(currentPosition)) { - Replace replace= new Replace(p, deltaOffset, event.getLength(), event.getText()); - ((IDocumentExtension) document).registerPostNotificationReplace(this, replace); + int deltaOffset = event.getOffset() - currentPosition.getOffset(); + + if (fListener != null) { + int length = event.getText() == null ? 0 : event.getText().length(); + fListener.setCurrentPosition(currentPosition, deltaOffset + length); + } + + for (int i = 0; i != positions.length; i++) { + TypedPosition p = (TypedPosition) positions[i]; + + if (p.getType().equals(currentPosition.getType()) + && !p.equals(currentPosition)) { + Replace replace = new Replace(p, deltaOffset, + event.getLength(), event.getText()); + ((IDocumentExtension) document) + .registerPostNotificationReplace(this, replace); } } } - + /* * @see IPositionUpdater#update(DocumentEvent) */ public void update(DocumentEvent event) { - int deltaLength= event.getText().length() - event.getLength(); - - Position[] positions= getPositions(event.getDocument()); - TypedPosition currentPosition= (TypedPosition) findCurrentPosition(positions, event.getOffset()); - // document change outside positions - if (currentPosition == null) { - - for (int i= 0; i != positions.length; i++) { - TypedPosition position= (TypedPosition) positions[i]; - int offset= position.getOffset(); - - if (offset >= event.getOffset()) - position.setOffset(offset + deltaLength); + int eventOffset = event.getOffset(); + int eventOldLength = event.getLength(); + int eventNewLength = event.getText() == null ? 0 : event.getText() + .length(); + int deltaLength = eventNewLength - eventOldLength; + + Position[] positions = getPositions(event.getDocument()); + + for (int i = 0; i != positions.length; i++) { + + Position position = positions[i]; + + if (position.isDeleted()) + continue; + + int offset = position.getOffset(); + int length = position.getLength(); + int end = offset + length; + + if (offset > eventOffset + eventOldLength) // position comes way + // after change - shift + position.setOffset(offset + deltaLength); + else if (end < eventOffset) // position comes way before change - + // leave alone + ; + else if (offset <= eventOffset + && end >= eventOffset + eventOldLength) { + // event completely internal to the position - adjust length + position.setLength(length + deltaLength); + } else if (offset < eventOffset) { + // event extends over end of position - adjust length + int newEnd = eventOffset + eventNewLength; + position.setLength(newEnd - offset); + } else if (end > eventOffset + eventOldLength) { + // event extends from before position into it - adjust offset + // and length + // offset becomes end of event, length ajusted acordingly + // we want to recycle the overlapping part + int newOffset = eventOffset + eventNewLength; + position.setOffset(newOffset); + position.setLength(length + deltaLength); + } else { + // event consumes the position - delete it + position.delete(); + // JavaPlugin.log(new Status(IStatus.INFO, + // JavaPlugin.getPluginId(), IStatus.OK, "linked position + // deleted -> must leave: "+fPositionCategoryName, null)); + // //$NON-NLS-1$ + fMustLeave = true; } - - // document change within a position - } else { - int length= currentPosition.getLength(); - - for (int i= 0; i != positions.length; i++) { - TypedPosition position= (TypedPosition) positions[i]; - int offset= position.getOffset(); - - if (position.equals(currentPosition)) { - position.setLength(length + deltaLength); - } else if (offset > currentPosition.getOffset()) { - position.setOffset(offset + deltaLength); - } - } } + + if (fMustLeave) + abort(); } private static Position findCurrentPosition(Position[] positions, int offset) { - for (int i= 0; i != positions.length; i++) + for (int i = 0; i != positions.length; i++) if (includes(positions[i], offset, 0)) return positions[i]; - - return null; - } - - private static Position findCurrentEditablePosition(Position[] positions, int offset) { - Position position= positions[0]; - while ((position != null) && !includes(position, offset, 0)) - position= findNextPosition(positions, position.getOffset()); - - return position; + return null; } private boolean containsLineDelimiters(String string) { - String[] delimiters= fDocument.getLegalLineDelimiters(); - for (int i= 0; i != delimiters.length; i++) + if (string == null) + return false; + + String[] delimiters = fDocument.getLegalLineDelimiters(); + + for (int i = 0; i != delimiters.length; i++) if (string.indexOf(delimiters[i]) != -1) return true; return false; } - + /** * Test if ok to modify through UI. */ public boolean anyPositionIncludes(int offset, int length) { - Position[] positions= getPositions(fDocument); + Position[] positions = getPositions(fDocument); - Position position= findCurrentEditablePosition(positions, offset); + Position position = findCurrentPosition(positions, offset); if (position == null) return false; - + return includes(position, offset, length); } - + + /** + * Returns the position that includes the given range. + * + * @param offset + * @param length + * @return position that includes the given range + */ + public Position getEmbracingPosition(int offset, int length) { + Position[] positions = getPositions(fDocument); + + Position position = findCurrentPosition(positions, offset); + if (position != null && includes(position, offset, length)) + return position; + + return null; + } + + /* + * @see org.eclipse.jface.text.IAutoIndentStrategy#customizeDocumentCommand(org.eclipse.jface.text.IDocument, + * org.eclipse.jface.text.DocumentCommand) + */ + public void customizeDocumentCommand(IDocument document, + DocumentCommand command) { + + if (fMustLeave) { + leave(true); + return; + } + + // don't interfere with preceding auto edit strategies + if (command.getCommandCount() != 1) { + leave(true); + return; + } + + Position[] positions = getPositions(document); + TypedPosition currentPosition = (TypedPosition) findCurrentPosition( + positions, command.offset); + + // handle edits outside of a position + if (currentPosition == null) { + leave(true); + return; + } + + if (!command.doit) + return; + + command.doit = false; + command.owner = this; + command.caretOffset = command.offset + command.length; + + int deltaOffset = command.offset - currentPosition.getOffset(); + + if (fListener != null) + fListener.setCurrentPosition(currentPosition, deltaOffset + + command.text.length()); + + for (int i = 0; i != positions.length; i++) { + TypedPosition position = (TypedPosition) positions[i]; + + try { + if (position.getType().equals(currentPosition.getType()) + && !position.equals(currentPosition)) + command.addCommand(position.getOffset() + deltaOffset, + command.length, command.text, this); + } catch (BadLocationException e) { + PHPeclipsePlugin.log(e); + } + } + } + }