X-Git-Url: http://git.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 0745ef7..4fb0216 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,13 +1,13 @@
-/**********************************************************************
-Copyright (c) 2000, 2002 IBM Corp. 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 implementation
-**********************************************************************/
+/*******************************************************************************
+ * 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;
@@ -18,6 +18,7 @@ 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;
@@ -29,7 +30,7 @@ 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.jface.text.contentassist.ICompletionProposal;
/**
@@ -99,35 +100,55 @@ public class LinkedPositionManager implements IDocumentListener, IPositionUpdate
}
}
- private static final String LINKED_POSITION= "LinkedPositionManager.linked.position"; //$NON-NLS-1$
+ 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
.
*
* @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) {
+ public void setLinkedPositionListener(ILinkedPositionListener listener) {
fListener= listener;
}
/**
- * Adds a linked position to the manager.
+ * 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:
*
*
+ * There are the following constraints for linked positions: + * + *
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:
+ *
+ * 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() {
- LinkedPositionManager manager= (LinkedPositionManager) fgActiveManagers.get(fDocument);
- if (manager != null)
- manager.leave(true);
-
- fgActiveManagers.put(fDocument, this);
+
+ 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$
+ }
- fDocument.addPositionCategory(LINKED_POSITION);
+ 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) {
- 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());
- }
- }
+ 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);
- fDocument.removePositionCategory(LINKED_POSITION);
-
- } 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);
+ 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);
+ }
}
+
}
/**
@@ -240,6 +370,22 @@ public class LinkedPositionManager implements IDocumentListener, IPositionUpdate
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
.
@@ -287,22 +433,28 @@ public class LinkedPositionManager implements IDocumentListener, IPositionUpdate
Position lastPosition= null;
Position position= getFirstPosition();
- while ((position != null) && (position.getOffset() < offset) && !((TypedPosition) position).getType().equals(currentType)) {
- lastPosition= position;
+ 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;
} catch (BadPositionCategoryException e) {
- PHPeclipsePlugin.log(e);
+ PHPeclipsePlugin.log(e);
Assert.isTrue(false);
}
@@ -331,10 +483,23 @@ public class LinkedPositionManager implements IDocumentListener, IPositionUpdate
}
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
}
/*
@@ -342,6 +507,11 @@ public class LinkedPositionManager implements IDocumentListener, IPositionUpdate
*/
public void documentAboutToBeChanged(DocumentEvent event) {
+ if (fMustLeave) {
+ event.getDocument().removeDocumentListener(this);
+ return;
+ }
+
IDocument document= event.getDocument();
Position[] positions= getPositions(document);
@@ -351,7 +521,7 @@ public class LinkedPositionManager implements IDocumentListener, IPositionUpdate
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) &&
+ (findCurrentPosition(positions, event.getOffset()) != null) && // will never become true, see condition above
(findCurrentPosition(positions, event.getOffset() + event.getLength()) != null))
{
leave(true);
@@ -409,37 +579,54 @@ public class LinkedPositionManager implements IDocumentListener, IPositionUpdate
* @see IPositionUpdater#update(DocumentEvent)
*/
public void update(DocumentEvent event) {
- int deltaLength= (event.getText() == null ? 0 : event.getText().length()) - event.getLength();
+
+ 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());
- TypedPosition currentPosition= (TypedPosition) findCurrentPosition(positions, event.getOffset());
-
- // document change outside positions
- if (currentPosition == null) {
+
+
+ for (int i= 0; i != positions.length; i++) {
- 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);
- }
+ Position position= positions[i];
- // 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 (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) {
@@ -477,10 +664,31 @@ public class LinkedPositionManager implements IDocumentListener, IPositionUpdate
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) {
@@ -516,9 +724,9 @@ public class LinkedPositionManager implements IDocumentListener, IPositionUpdate
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);
+ PHPeclipsePlugin.log(e);
}
}
}
-}
\ No newline at end of file
+}