From dc9e7d2fc4245a64183c7529f5dfa3d3cd6239e2 Mon Sep 17 00:00:00 2001 From: khartlage Date: Mon, 9 Dec 2002 18:23:11 +0000 Subject: [PATCH] fixed bug in template expansion --- .../ui/text/link/LinkedPositionListener.java | 31 ++ .../ui/text/link/LinkedPositionManager.java | 448 +++++++++++++++++ .../ui/text/link/LinkedPositionMessages.java | 43 ++ .../ui/text/link/LinkedPositionMessages.properties | 9 + .../internal/ui/text/link/LinkedPositionUI.java | 526 ++++++++++++++++++++ .../ui/text/template/TemplateProposal.java | 29 +- .../phpeclipse/IPreferenceConstants.java | 2 + .../sourceforge/phpeclipse/PHPeclipsePlugin.java | 3 +- .../phpeditor/util/PHPColorProvider.java | 2 + 9 files changed, 1078 insertions(+), 15 deletions(-) create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/link/LinkedPositionListener.java create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/link/LinkedPositionManager.java create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/link/LinkedPositionMessages.java create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/link/LinkedPositionMessages.properties create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/link/LinkedPositionUI.java diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/link/LinkedPositionListener.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/link/LinkedPositionListener.java new file mode 100644 index 0000000..94028c9 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/link/LinkedPositionListener.java @@ -0,0 +1,31 @@ +/* + * (c) Copyright IBM Corp. 2000, 2001. + * All Rights Reserved. + */ +package net.sourceforge.phpdt.internal.ui.text.link; + +import org.eclipse.jface.text.IDocumentExtension; +import org.eclipse.jface.text.Position; + +/** + * A listener for highlight change notification and exititing linked mode. + */ +public interface LinkedPositionListener { + + /** + * Notifies that the linked mode has been left. On success, all changes + * are kept, otherwise all changes made to the linked positions are restored + * to the state before entering linked mode. + */ + void exit(boolean success); + + /** + * Notifies the changed linked position. The listener is asked + * to reposition the caret at the given offset. + * + * @param position the linked position which initiated the change. + * @param caretOffset the caret offset relative to the position. + */ + void setCurrentPosition(Position position, int caretOffset); + +} 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 new file mode 100644 index 0000000..4ce53ee --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/link/LinkedPositionManager.java @@ -0,0 +1,448 @@ +/* + * (c) Copyright IBM Corp. 2000, 2001. + * All Rights Reserved. + */ +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.BadLocationException; +import org.eclipse.jface.text.BadPositionCategoryException; +import org.eclipse.jface.text.DocumentEvent; +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; + +/** + * 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(); + } + } + + 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 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 IDocument fDocument; + + private LinkedPositionListener fListener; + + /** + * Creates a LinkedPositionManager for a IDocument. + * + * @param document the document to use with linked positions. + */ + public LinkedPositionManager(IDocument document) { + Assert.isNotNull(document); + + fDocument= document; + install(); + } + + /** + * Sets a listener to notify changes of current linked position. + */ + public void setLinkedPositionListener(LinkedPositionListener listener) { + fListener= listener; + } + + /** + * Adds a linked position 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. + */ + public void addPosition(int offset, int length) 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 type= fDocument.get(offset, length); + + if (containsLineDelimiters(type)) + throw new BadLocationException(LinkedPositionMessages.getString(("LinkedPositionManager.error.contains.line.delimiters"))); //$NON-NLS-1$ + + try { + fDocument.addPosition(LINKED_POSITION, new TypedPosition(offset, length, type)); + } 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); + + fDocument.addPositionCategory(LINKED_POSITION); + fDocument.addPositionUpdater(this); + fDocument.addDocumentListener(this); + } + + /** + * 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()); + } + } + + 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); + } + } + + /** + * Returns the first linked position. + * + * @return returns null if no linked position exist. + */ + public Position getFirstPosition() { + return getNextPosition(-1); + } + + /** + * 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; + + Position lastPosition= null; + Position position= getFirstPosition(); + + while ((position != null) && (position.getOffset() < offset)) { + lastPosition= position; + position= findNextPosition(positions, position.getOffset()); + } + + return lastPosition; + } + + private static Position[] getPositions(IDocument document) { + try { + Position[] positions= document.getPositions(LINKED_POSITION); + 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) { + uninstall(success); + + if (fListener != null) + fListener.exit(success); + } + + /* + * @see IDocumentListener#documentAboutToBeChanged(DocumentEvent) + */ + public void documentAboutToBeChanged(DocumentEvent event) { + IDocument document= event.getDocument(); + + Position[] positions= getPositions(document); + Position position= findCurrentEditablePosition(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 { + 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) { + IDocument document= event.getDocument(); + + Position[] positions= getPositions(document); + TypedPosition currentPosition= (TypedPosition) findCurrentEditablePosition(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); + } + } + } + + /* + * @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); + } + + // 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); + } + } + } + } + + 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 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; + } + + private boolean containsLineDelimiters(String string) { + 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= findCurrentEditablePosition(positions, offset); + if (position == null) + return false; + + return includes(position, offset, length); + } + +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/link/LinkedPositionMessages.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/link/LinkedPositionMessages.java new file mode 100644 index 0000000..4a6b8fb --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/link/LinkedPositionMessages.java @@ -0,0 +1,43 @@ +/* + * (c) Copyright IBM Corp. 2000, 2001. + * All Rights Reserved. + */ +package net.sourceforge.phpdt.internal.ui.text.link; + +import java.text.MessageFormat; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +public class LinkedPositionMessages { + + private static final String RESOURCE_BUNDLE= LinkedPositionMessages.class.getName(); + private static ResourceBundle fgResourceBundle= ResourceBundle.getBundle(RESOURCE_BUNDLE); + + private LinkedPositionMessages() { + } + + public static String getString(String key) { + try { + return fgResourceBundle.getString(key); + } catch (MissingResourceException e) { + return '!' + key + '!'; + } + } + + /** + * Gets a string from the resource bundle and formats it with the argument + * + * @param key the string used to get the bundle value, must not be null + */ + public static String getFormattedString(String key, Object arg) { + return MessageFormat.format(getString(key), new Object[] { arg }); + } + + + /** + * Gets a string from the resource bundle and formats it with arguments + */ + public static String getFormattedString(String key, Object[] args) { + return MessageFormat.format(getString(key), args); + } +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/link/LinkedPositionMessages.properties b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/link/LinkedPositionMessages.properties new file mode 100644 index 0000000..267939d --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/link/LinkedPositionMessages.properties @@ -0,0 +1,9 @@ +######################################### +# (c) Copyright IBM Corp. 2000, 2001. +# All Rights Reserved. +######################################### + +LinkedPositionUI.error.title=Error in LinkedPositionError + +LinkedPositionManager.error.contains.line.delimiters=String contains line delimiters. +LinkedPositionManager.error.position.collision=Linked position collides with another linked position. diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/link/LinkedPositionUI.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/link/LinkedPositionUI.java new file mode 100644 index 0000000..a9389ea --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/link/LinkedPositionUI.java @@ -0,0 +1,526 @@ +/* + * (c) Copyright IBM Corp. 2000, 2001. + * All Rights Reserved. + */ +package net.sourceforge.phpdt.internal.ui.text.link; + +import java.lang.reflect.InvocationTargetException; + +import net.sourceforge.phpeclipse.PHPeclipsePlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.preference.PreferenceConverter; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.BadPositionCategoryException; +import org.eclipse.jface.text.DefaultPositionUpdater; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IPositionUpdater; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextInputListener; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.ITextViewerExtension; +import org.eclipse.jface.text.Position; +import org.eclipse.jface.text.Region; +import org.eclipse.jface.util.Assert; +import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.jface.util.PropertyChangeEvent; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.custom.VerifyKeyListener; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.PaintEvent; +import org.eclipse.swt.events.PaintListener; +import org.eclipse.swt.events.VerifyEvent; +import org.eclipse.swt.events.VerifyListener; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; + +/** + * A user interface for LinkedPositionManager, using ITextViewer. + */ +public class LinkedPositionUI implements LinkedPositionListener, + ITextInputListener, ModifyListener, VerifyListener, VerifyKeyListener, PaintListener, IPropertyChangeListener { + + /** + * A listener for notification when the user cancelled the edit operation. + */ + public interface ExitListener { + void exit(boolean accept); + } + + /** Preference key for linked position color */ + // public final static String LINKED_POSITION_COLOR= "_linkedPositionColor"; //$NON-NLS-1$ + // leave flags + private static final int UNINSTALL= 1; // uninstall linked position manager + private static final int COMMIT= 2; // commit changes + private static final int DOCUMENT_CHANGED= 4; // document has changed + private static final int UPDATE_CARET= 8; // update caret + + private static final String CARET_POSITION= "LinkedPositionUI.caret.position"; //$NON-NLS-1$ + private static final IPositionUpdater fgUpdater= new DefaultPositionUpdater(CARET_POSITION); + private static final IPreferenceStore fgStore= PHPeclipsePlugin.getDefault().getPreferenceStore(); + + private final ITextViewer fViewer; + private final LinkedPositionManager fManager; + private Color fFrameColor; + + private int fFinalCaretOffset= -1; // no final caret offset + + private Position fFramePosition; + private int fCaretOffset; + + private ExitListener fExitListener; + + /** + * Creates a user interface for LinkedPositionManager. + * + * @param viewer the text viewer. + * @param manager the LinkedPositionManager managing a IDocument of the ITextViewer. + */ + public LinkedPositionUI(ITextViewer viewer, LinkedPositionManager manager) { + Assert.isNotNull(viewer); + Assert.isNotNull(manager); + + fViewer= viewer; + fManager= manager; + + fManager.setLinkedPositionListener(this); + + initializeHighlightColor(viewer); + } + + /* + * @see IPropertyChangeListener#propertyChange(PropertyChangeEvent) + */ + public void propertyChange(PropertyChangeEvent event) { + // if (event.getProperty().equals(CompilationUnitEditor.LINKED_POSITION_COLOR)) { + if (event.getProperty().equals(PHPeclipsePlugin.LINKED_POSITION_COLOR)) { + initializeHighlightColor(fViewer); + redrawRegion(); + } + } + + private void initializeHighlightColor(ITextViewer viewer) { + + if (fFrameColor != null) + fFrameColor.dispose(); + + StyledText text= viewer.getTextWidget(); + if (text != null) { + Display display= text.getDisplay(); + // fFrameColor= createColor(fgStore, CompilationUnitEditor.LINKED_POSITION_COLOR, display); + fFrameColor= createColor(fgStore, PHPeclipsePlugin.LINKED_POSITION_COLOR, display); + } + } + + /** + * Creates a color from the information stored in the given preference store. + * Returns null if there is no such information available. + */ + private Color createColor(IPreferenceStore store, String key, Display display) { + + RGB rgb= null; + + if (store.contains(key)) { + + if (store.isDefault(key)) + rgb= PreferenceConverter.getDefaultColor(store, key); + else + rgb= PreferenceConverter.getColor(store, key); + + if (rgb != null) + return new Color(display, rgb); + } + + return null; + } + + /** + * Sets the final position of the caret when the linked mode is exited + * successfully by leaving the last linked position using TAB. + */ + public void setFinalCaretOffset(int offset) { + fFinalCaretOffset= offset; + } + + /** + * Sets a CancelListener which is notified if the linked mode + * is exited unsuccessfully by hitting ESC. + */ + public void setCancelListener(ExitListener listener) { + fExitListener= listener; + } + + /* + * @see LinkedPositionManager.LinkedPositionListener#setCurrentPositions(Position, int) + */ + public void setCurrentPosition(Position position, int caretOffset) { + if (!fFramePosition.equals(position)) { + redrawRegion(); + fFramePosition= position; + } + + fCaretOffset= caretOffset; + } + + /** + * Enters the linked mode. The linked mode can be left by calling + * exit. + * + * @see #exit(boolean) + */ + public void enter() { + // track final caret + IDocument document= fViewer.getDocument(); + document.addPositionCategory(CARET_POSITION); + document.addPositionUpdater(fgUpdater); + try { + if (fFinalCaretOffset != -1) + document.addPosition(CARET_POSITION, new Position(fFinalCaretOffset)); + } catch (BadLocationException e) { + handleException(fViewer.getTextWidget().getShell(), e); + + } catch (BadPositionCategoryException e) { + PHPeclipsePlugin.log(e); + Assert.isTrue(false); + } + + fViewer.addTextInputListener(this); + + ITextViewerExtension extension= (ITextViewerExtension) fViewer; + extension.prependVerifyKeyListener(this); + + StyledText text= fViewer.getTextWidget(); + text.addVerifyListener(this); + text.addModifyListener(this); + text.addPaintListener(this); + text.showSelection(); + + fFramePosition= fManager.getFirstPosition(); + if (fFramePosition == null) + leave(UNINSTALL | COMMIT | UPDATE_CARET); + + fgStore.addPropertyChangeListener(this); + } + + /* + * @see LinkedPositionManager.LinkedPositionListener#exit(boolean) + */ + public void exit(boolean success) { + // no UNINSTALL since manager has already uninstalled itself + leave((success ? COMMIT : 0) | UPDATE_CARET); + } + + /** + * Returns the cursor selection, after having entered the linked mode. + * enter() must be called prior to a call to this method. + */ + public IRegion getSelectedRegion() { + if (fFramePosition == null) + return new Region(fFinalCaretOffset, 0); + else + return new Region(fFramePosition.getOffset(), fFramePosition.getLength()); + } + + private void leave(int flags) { + if ((flags & UNINSTALL) != 0) + fManager.uninstall((flags & COMMIT) != 0); + + fgStore.removePropertyChangeListener(this); + + if (fFrameColor != null) { + fFrameColor.dispose(); + fFrameColor= null; + } + + StyledText text= fViewer.getTextWidget(); + text.removePaintListener(this); + text.removeModifyListener(this); + text.removeVerifyListener(this); + + ITextViewerExtension extension= (ITextViewerExtension) fViewer; + extension.removeVerifyKeyListener(this); + + fViewer.removeTextInputListener(this); + + try { + IRegion region= fViewer.getVisibleRegion(); + IDocument document= fViewer.getDocument(); + + if (((flags & COMMIT) != 0) && + ((flags & DOCUMENT_CHANGED) == 0) && + ((flags & UPDATE_CARET) != 0)) + { + Position[] positions= document.getPositions(CARET_POSITION); + + if ((positions != null) && (positions.length != 0)) { + int offset= positions[0].getOffset() - region.getOffset(); + if ((offset >= 0) && (offset <= region.getLength())) + text.setSelection(offset, offset); + } + } + + document.removePositionUpdater(fgUpdater); + document.removePositionCategory(CARET_POSITION); + + if (fExitListener != null) + fExitListener.exit( + ((flags & COMMIT) != 0) || + ((flags & DOCUMENT_CHANGED) != 0)); + + } catch (BadPositionCategoryException e) { + PHPeclipsePlugin.log(e); + Assert.isTrue(false); + } + + if ((flags & DOCUMENT_CHANGED) == 0) + text.redraw(); + } + + private void next() { + redrawRegion(); + + fFramePosition= fManager.getNextPosition(fFramePosition.getOffset()); + if (fFramePosition == null) { + leave(UNINSTALL | COMMIT | UPDATE_CARET); + } else { + selectRegion(); + redrawRegion(); + } + } + + private void previous() { + redrawRegion(); + + Position position= fManager.getPreviousPosition(fFramePosition.getOffset()); + if (position == null) { + fViewer.getTextWidget().getDisplay().beep(); + } else { + fFramePosition= position; + selectRegion(); + redrawRegion(); + } + } + + /* + * @see VerifyKeyListener#verifyKey(VerifyEvent) + */ + public void verifyKey(VerifyEvent event) { + switch (event.character) { + // [SHIFT-]TAB = hop between edit boxes + case 0x09: + { + Point selection= fViewer.getTextWidget().getSelection(); + IRegion region= fViewer.getVisibleRegion(); + int offset= selection.x + region.getOffset(); + int length= selection.y - selection.x; + + // if tab was treated as a document change, would it exceed variable range? + if (!LinkedPositionManager.includes(fFramePosition, offset, length)) { + leave(UNINSTALL | COMMIT | UPDATE_CARET); + return; + } + } + + if (event.stateMask == SWT.SHIFT) + previous(); + else + next(); + + event.doit= false; + break; + + // ENTER + case 0x0D: + leave(UNINSTALL | COMMIT | UPDATE_CARET); + event.doit= false; + break; + + // ESC + case 0x1B: + leave(UNINSTALL | COMMIT); + event.doit= false; + break; + } + } + + /* + * @see VerifyListener#verifyText(VerifyEvent) + */ + public void verifyText(VerifyEvent event) { + if (!event.doit) + return; + + IRegion region= fViewer.getVisibleRegion(); + + int offset= event.start + region.getOffset(); + int length= event.end - event.start; + + // allow changes only within linked positions when coming through UI + if (!fManager.anyPositionIncludes(offset, length)) + leave(UNINSTALL | COMMIT); + } + + /* + * @see PaintListener#paintControl(PaintEvent) + */ + public void paintControl(PaintEvent event) { + if (fFramePosition == null) + return; + + IRegion region= fViewer.getVisibleRegion(); + + // #6824 + if (!includes(region, fFramePosition)) { + leave(UNINSTALL | COMMIT | DOCUMENT_CHANGED); + return; + } + + int offset= fFramePosition.getOffset() - region.getOffset(); + int length= fFramePosition.getLength(); + + StyledText text= fViewer.getTextWidget(); + + // support for bidi + Point minLocation= getMinimumLocation(text, offset, length); + Point maxLocation= getMaximumLocation(text, offset, length); + + int x1= minLocation.x; + int x2= minLocation.x + maxLocation.x - minLocation.x - 1; + int y= minLocation.y + text.getLineHeight() - 1; + + GC gc= event.gc; + gc.setForeground(fFrameColor); + gc.drawLine(x1, y, x2, y); + } + + private static Point getMinimumLocation(StyledText text, int offset, int length) { + Point minLocation= new Point(Integer.MAX_VALUE, Integer.MAX_VALUE); + + for (int i= 0; i <= length; i++) { + Point location= text.getLocationAtOffset(offset + i); + + if (location.x < minLocation.x) + minLocation.x= location.x; + if (location.y < minLocation.y) + minLocation.y= location.y; + } + + return minLocation; + } + + private static Point getMaximumLocation(StyledText text, int offset, int length) { + Point maxLocation= new Point(Integer.MIN_VALUE, Integer.MIN_VALUE); + + for (int i= 0; i <= length; i++) { + Point location= text.getLocationAtOffset(offset + i); + + if (location.x > maxLocation.x) + maxLocation.x= location.x; + if (location.y > maxLocation.y) + maxLocation.y= location.y; + } + + return maxLocation; + } + + private void redrawRegion() { + IRegion region= fViewer.getVisibleRegion(); + + if (!includes(region, fFramePosition)) { + leave(UNINSTALL | COMMIT | DOCUMENT_CHANGED); + return; + } + + int offset= fFramePosition.getOffset() - region.getOffset(); + int length= fFramePosition.getLength(); + + StyledText text= fViewer.getTextWidget(); + if (text != null && !text.isDisposed()) + text.redrawRange(offset, length, true); + } + + private void selectRegion() { + IRegion region= fViewer.getVisibleRegion(); + + if (!includes(region, fFramePosition)) { + leave(UNINSTALL | COMMIT | DOCUMENT_CHANGED); + return; + } + + int start= fFramePosition.getOffset() - region.getOffset(); + int end= fFramePosition.getLength() + start; + + StyledText text= fViewer.getTextWidget(); + if (text != null && !text.isDisposed()) + text.setSelection(start, end); + } + + private void updateCaret() { + IRegion region= fViewer.getVisibleRegion(); + + if (!includes(region, fFramePosition)) { + leave(UNINSTALL | COMMIT | DOCUMENT_CHANGED); + return; + } + + int offset= fFramePosition.getOffset() + fCaretOffset - region.getOffset(); + + if ((offset >= 0) && (offset <= region.getLength())) { + StyledText text= fViewer.getTextWidget(); + if (text != null && !text.isDisposed()) + text.setCaretOffset(offset); + } + } + + /* + * @see ModifyListener#modifyText(ModifyEvent) + */ + public void modifyText(ModifyEvent e) { + // reposition caret after StyledText + redrawRegion(); + updateCaret(); + } + + private static void handleException(Shell shell, Exception e) { + String title= LinkedPositionMessages.getString("LinkedPositionUI.error.title"); //$NON-NLS-1$ + if (e instanceof CoreException) + PHPeclipsePlugin.log(e); + // ExceptionHandler.handle((CoreException)e, shell, title, null); + else if (e instanceof InvocationTargetException) + PHPeclipsePlugin.log(e); + // ExceptionHandler.handle((InvocationTargetException)e, shell, title, null); + else { + MessageDialog.openError(shell, title, e.getMessage()); + PHPeclipsePlugin.log(e); + } + } + + /* + * @see ITextInputListener#inputDocumentAboutToBeChanged(IDocument, IDocument) + */ + public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) { + // 5326: leave linked mode on document change + int flags= UNINSTALL | COMMIT | (oldInput.equals(newInput) ? 0 : DOCUMENT_CHANGED); + leave(flags); + } + + /* + * @see ITextInputListener#inputDocumentChanged(IDocument, IDocument) + */ + public void inputDocumentChanged(IDocument oldInput, IDocument newInput) { + } + + private static boolean includes(IRegion region, Position position) { + return + position.getOffset() >= region.getOffset() && + position.getOffset() + position.getLength() <= region.getOffset() + region.getLength(); + } + +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/template/TemplateProposal.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/template/TemplateProposal.java index 5178caa..ca3ac38 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/template/TemplateProposal.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/template/TemplateProposal.java @@ -9,10 +9,13 @@ import net.sourceforge.phpdt.internal.corext.template.TemplateBuffer; import net.sourceforge.phpdt.internal.corext.template.TemplateContext; import net.sourceforge.phpdt.internal.corext.template.TemplateMessages; import net.sourceforge.phpdt.internal.corext.template.TemplatePosition; -import net.sourceforge.phpeclipse.PHPeclipsePlugin; -import org.eclipse.core.runtime.CoreException; import net.sourceforge.phpdt.internal.corext.template.java.CompilationUnitContext; import net.sourceforge.phpdt.internal.corext.template.java.JavaTemplateMessages; +import net.sourceforge.phpdt.internal.ui.text.java.IJavaCompletionProposal; +import net.sourceforge.phpeclipse.PHPeclipsePlugin; +import org.eclipse.core.runtime.CoreException; +import net.sourceforge.phpdt.internal.ui.text.link.LinkedPositionManager; +import net.sourceforge.phpdt.internal.ui.text.link.LinkedPositionUI; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; @@ -22,8 +25,6 @@ import org.eclipse.jface.text.contentassist.IContextInformation; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.widgets.Shell; -//import org.eclipse.jdt.internal.ui.JavaPlugin; -import net.sourceforge.phpdt.internal.ui.text.java.IJavaCompletionProposal; //import org.eclipse.jdt.internal.ui.text.link.LinkedPositionManager; //import org.eclipse.jdt.internal.ui.text.link.LinkedPositionUI; //import org.eclipse.jdt.internal.ui.util.ExceptionHandler; @@ -41,7 +42,7 @@ public class TemplateProposal implements IJavaCompletionProposal { private TemplateBuffer fTemplateBuffer; private String fOldText; -// private IRegion fSelectedRegion; // initialized by apply() + private IRegion fSelectedRegion; // initialized by apply() /** * Creates a template proposal with a template and its context. @@ -78,7 +79,7 @@ public class TemplateProposal implements IJavaCompletionProposal { document.replace(start, end - start, templateString); // translate positions - // LinkedPositionManager manager= new LinkedPositionManager(document); + LinkedPositionManager manager= new LinkedPositionManager(document); TemplatePosition[] variables= fTemplateBuffer.getVariables(); for (int i= 0; i != variables.length; i++) { TemplatePosition variable= variables[i]; @@ -89,15 +90,15 @@ public class TemplateProposal implements IJavaCompletionProposal { int[] offsets= variable.getOffsets(); int length= variable.getLength(); -// for (int j= 0; j != offsets.length; j++) -// manager.addPosition(offsets[j] + start, length); + for (int j= 0; j != offsets.length; j++) + manager.addPosition(offsets[j] + start, length); } -// LinkedPositionUI editor= new LinkedPositionUI(fViewer, manager); -// editor.setFinalCaretOffset(getCaretOffset(fTemplateBuffer) + start); -// editor.enter(); + LinkedPositionUI editor= new LinkedPositionUI(fViewer, manager); + editor.setFinalCaretOffset(getCaretOffset(fTemplateBuffer) + start); + editor.enter(); -// fSelectedRegion= editor.getSelectedRegion(); + fSelectedRegion= editor.getSelectedRegion(); } catch (BadLocationException e) { PHPeclipsePlugin.log(e); @@ -124,8 +125,8 @@ public class TemplateProposal implements IJavaCompletionProposal { * @see ICompletionProposal#getSelection(IDocument) */ public Point getSelection(IDocument document) { -// return new Point(fSelectedRegion.getOffset(), fSelectedRegion.getLength()); - return null; + return new Point(fSelectedRegion.getOffset(), fSelectedRegion.getLength()); +// return null; } /* diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/IPreferenceConstants.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/IPreferenceConstants.java index ac605f0..88f3dd7 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/IPreferenceConstants.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/IPreferenceConstants.java @@ -59,5 +59,7 @@ public interface IPreferenceConstants { public static final String PHP_STRING = "_php_string"; public static final String PHP_DEFAULT = "_php_default"; + public static final String LINKED_POSITION_COLOR= "_linkedPositionColor"; + } \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/PHPeclipsePlugin.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/PHPeclipsePlugin.java index 7c46c83..dc81130 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/PHPeclipsePlugin.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/PHPeclipsePlugin.java @@ -270,8 +270,9 @@ public class PHPeclipsePlugin extends AbstractUIPlugin implements IPreferenceCon PreferenceConverter.setDefault(store, PHP_KEYWORD, PHPColorProvider.KEYWORD); PreferenceConverter.setDefault(store, PHP_VARIABLE, PHPColorProvider.VARIABLE); PreferenceConverter.setDefault(store, PHP_FUNCTIONNAME, PHPColorProvider.FUNCTION_NAME); - PreferenceConverter.setDefault(store, PHP_STRING, PHPColorProvider.STRING); + PreferenceConverter.setDefault(store, PHP_STRING, PHPColorProvider.STRING); PreferenceConverter.setDefault(store, PHP_DEFAULT, PHPColorProvider.DEFAULT); + PreferenceConverter.setDefault(store, LINKED_POSITION_COLOR, PHPColorProvider.LINKED_POSITION_COLOR); } diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/util/PHPColorProvider.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/util/PHPColorProvider.java index 48d7527..607d90d 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/util/PHPColorProvider.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/util/PHPColorProvider.java @@ -30,6 +30,8 @@ public class PHPColorProvider { public static final RGB FUNCTION_NAME= new RGB(127, 127, 159); public static final RGB STRING= new RGB(42, 0, 255); public static final RGB DEFAULT= new RGB(0, 0, 0); + + public static final RGB LINKED_POSITION_COLOR= new RGB(0, 0, 0); protected Map fColorTable= new HashMap(10); -- 1.7.1