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 deleted file mode 100644 index fe1c763..0000000 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/link/LinkedPositionManager.java +++ /dev/null @@ -1,829 +0,0 @@ -/******************************************************************************* - * 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; -import java.util.Comparator; -import java.util.HashMap; -import java.util.Map; - -import net.sourceforge.phpeclipse.PHPeclipsePlugin; - -import org.eclipse.jface.text.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.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. - * - * The manager remains active on a document until any of the following actions - * occurs: - * - * - */ -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 void perform(IDocument document, IDocumentListener owner) { - document.removeDocumentListener(owner); - try { - document.replace(fReplacePosition.getOffset() - + fReplaceDeltaOffset, fReplaceLength, fReplaceText); - } catch (BadLocationException e) { - PHPeclipsePlugin.log(e); - // TBD - } - document.addDocumentListener(owner); - } - } - - 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 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. - * - * @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, boolean canCoexist) { - Assert.isNotNull(document); - 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(ILinkedPositionListener listener) { - fListener = listener; - } - - /** - * 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. - */ - public void addPosition(int offset, int length) throws BadLocationException { - 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$ - } - - 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 TypedPosition( - offset, length, type)); - } catch (BadPositionCategoryException e) { - PHPeclipsePlugin.log(e); - Assert.isTrue(false); - } - } - - /** - * 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; - } - - 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$ - } - - if (!canCoexist) { - LinkedPositionManager manager = (LinkedPositionManager) fgActiveManagers - .get(fDocument); - if (manager != null) - manager.leave(true); - } - - fgActiveManagers.put(fDocument, 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. - */ - public void uninstall(boolean success) { - - 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(fPositionCategoryName); - - fIsActive = false; - // JavaPlugin.log(new Status(IStatus.INFO, - // JavaPlugin.getPluginId(), IStatus.OK, "LinkedPositionManager - // deactivated: "+fPositionCategoryName, new Exception())); - // //$NON-NLS-1$ - - } 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; - } - - /** - * Returns the first linked position. - * - * @return returns null if no linked position exist. - */ - public Position getFirstPosition() { - 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. - * - * @return returns null if no linked position exist. - */ - public Position getNextPosition(int offset) { - 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++) { - if (positions[i].getOffset() > offset) { - 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 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); - if (positions == null) - return null; - - 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 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(fPositionCategoryName); - Arrays.sort(positions, fgPositionComparator); - return positions; - - } catch (BadPositionCategoryException e) { - 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()); - } - - 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); - } - - private void leave(boolean 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(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) { - - 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) { - // 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 - } else { - // modificaction inside editable position - if (includes(position, event.getOffset(), event.getLength())) { - if (containsLineDelimiters(event.getText())) - leave(true); - - // modificaction exceeds editable position - } else { - leave(true); - } - } - } - - /* - * @see IDocumentListener#documentChanged(DocumentEvent) - */ - public void documentChanged(DocumentEvent event) { - - // 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) { - 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 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; - } - } - - if (fMustLeave) - abort(); - } - - private static Position findCurrentPosition(Position[] positions, int offset) { - for (int i = 0; i != positions.length; i++) - if (includes(positions[i], offset, 0)) - return positions[i]; - - return null; - } - - private boolean containsLineDelimiters(String string) { - - 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 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); - } - } - } - -}