Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorteicher2005-05-17 12:53:31 +0000
committerteicher2005-05-17 12:53:31 +0000
commitcde44bc86d4bf6af3ec3f3693ed9f6f57c5a16ab (patch)
treeee4f9cd3388832ca9ed3a32750f0faf52c8b7c51 /org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/texteditor/CompoundEditExitStrategy.java
parent2eda3a34139bb073898849da15fe35cde63b7026 (diff)
downloadeclipse.platform.text-cde44bc86d4bf6af3ec3f3693ed9f6f57c5a16ab.tar.gz
eclipse.platform.text-cde44bc86d4bf6af3ec3f3693ed9f6f57c5a16ab.tar.xz
eclipse.platform.text-cde44bc86d4bf6af3ec3f3693ed9f6f57c5a16ab.zip
Bug 84353 [typing] Hippie completion fills undo stack
- added CompoundEditExitStrategy that detects end-of-compound-edit events - used by (Java)MoveLinesAction, HippieCompleteAction
Diffstat (limited to 'org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/texteditor/CompoundEditExitStrategy.java')
-rw-r--r--org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/texteditor/CompoundEditExitStrategy.java236
1 files changed, 236 insertions, 0 deletions
diff --git a/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/texteditor/CompoundEditExitStrategy.java b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/texteditor/CompoundEditExitStrategy.java
new file mode 100644
index 00000000000..600235d0ec4
--- /dev/null
+++ b/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/texteditor/CompoundEditExitStrategy.java
@@ -0,0 +1,236 @@
+package org.eclipse.ui.internal.texteditor;
+
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.custom.VerifyKeyListener;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.VerifyEvent;
+
+import org.eclipse.jface.text.ITextViewer;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IExecutionListener;
+import org.eclipse.core.commands.NotHandledException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.commands.ICommandService;
+
+/**
+ * Exit strategy for commands that want to fold repeated execution into one compound edit. See
+ * {@link org.eclipse.jface.text.IRewriteTarget#endCompoundChange() IRewriteTarget.endCompoundChange}.
+ * As long as a strategy is installed on an {@link ITextViewer}, it will detect the end of a
+ * compound operation when any of the following conditions becomes true:
+ * <ul>
+ * <li>the viewer's text widget loses the keyboard focus</li>
+ * <li>the mouse is clicked or double clicked inside the viewer's widget</li>
+ * <li>a command other than the ones specified is executed</li>
+ * <li>the viewer receives any key events that are not modifier combinations</li>
+ * </ul>
+ * <p>
+ * If the end of a compound edit is detected, any registered {@link ICompoundEditListener}s are
+ * notified and the strategy is disarmed (spring-loaded).
+ * </p>
+ *
+ * @since 3.1
+ */
+public final class CompoundEditExitStrategy {
+ /**
+ * Listens for events that may trigger the end of a compound edit.
+ */
+ private final class EventListener implements MouseListener, FocusListener, VerifyKeyListener, IExecutionListener {
+
+ /*
+ * @see org.eclipse.swt.events.MouseListener#mouseDoubleClick(org.eclipse.swt.events.MouseEvent)
+ */
+ public void mouseDoubleClick(MouseEvent e) {
+ // mouse actions end the compound change
+ fireEndCompoundEdit();
+ }
+
+ /*
+ * @see org.eclipse.swt.events.MouseListener#mouseDown(org.eclipse.swt.events.MouseEvent)
+ */
+ public void mouseDown(MouseEvent e) {
+ // mouse actions end the compound change
+ fireEndCompoundEdit();
+ }
+
+ public void mouseUp(MouseEvent e) {}
+
+ public void focusGained(FocusEvent e) {}
+
+ /*
+ * @see org.eclipse.swt.events.FocusListener#focusLost(org.eclipse.swt.events.FocusEvent)
+ */
+ public void focusLost(FocusEvent e) {
+ // losing focus ends the change
+ fireEndCompoundEdit();
+ }
+
+ public void notHandled(String commandId, NotHandledException exception) {}
+
+ public void postExecuteFailure(String commandId, ExecutionException exception) {}
+
+ public void postExecuteSuccess(String commandId, Object returnValue) {}
+
+ /*
+ * @see org.eclipse.core.commands.IExecutionListener#preExecute(java.lang.String, org.eclipse.core.commands.ExecutionEvent)
+ */
+ public void preExecute(String commandId, ExecutionEvent event) {
+ // any command other than the known ones end the compound change
+ for (int i= 0; i < fCommandIds.length; i++) {
+ if (commandId.equals(fCommandIds[i]))
+ return;
+ }
+ fireEndCompoundEdit();
+ }
+
+ /*
+ * @see org.eclipse.swt.custom.VerifyKeyListener#verifyKey(org.eclipse.swt.events.VerifyEvent)
+ */
+ public void verifyKey(VerifyEvent event) {
+ // any key press that is not a modifier combo ends the compound change
+ final int maskWithoutShift= SWT.MODIFIER_MASK & ~SWT.SHIFT;
+ if ((event.keyCode & SWT.MODIFIER_MASK) == 0 && (event.stateMask & maskWithoutShift) == 0)
+ fireEndCompoundEdit();
+ }
+
+ }
+
+ private final String[] fCommandIds;
+ private final EventListener fEventListener= new EventListener();
+ private final ListenerList fListenerList= new ListenerList();
+ private final ListenerList.INotifier fNotifier= new ListenerList.INotifier() {
+ public void notifyListener(Object listener) {
+ try {
+ ((ICompoundEditListener) listener).endCompoundEdit();
+ } catch (Exception e) {
+ IStatus status= new Status(IStatus.ERROR, TextEditorPlugin.PLUGIN_ID, IStatus.OK, "listener notification failed", e); //$NON-NLS-1$
+ TextEditorPlugin.getDefault().getLog().log(status);
+ }
+ }
+ };
+
+ private ITextViewer fViewer;
+ private StyledText fWidgetEventSource;
+
+ /**
+ * Creates a new strategy, equivalent to calling
+ * {@linkplain #CompoundEditExitStrategy(String[]) CompoundEditExitStrategy(new String[] &#x7b; commandId &#x7d;)}.
+ *
+ * @param commandId the command id of the repeatable command
+ */
+ public CompoundEditExitStrategy(String commandId) {
+ if (commandId == null)
+ throw new NullPointerException("commandId"); //$NON-NLS-1$
+ fCommandIds= new String[] {commandId};
+ }
+
+ /**
+ * Creates a new strategy, ending upon execution of any command other than the ones
+ * specified.
+ *
+ * @param commandIds the ids of the repeatable commands
+ */
+ public CompoundEditExitStrategy(String[] commandIds) {
+ for (int i= 0; i < commandIds.length; i++) {
+ if (commandIds[i] == null)
+ throw new NullPointerException("commandIds[" + i + "]"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ fCommandIds= new String[commandIds.length];
+ System.arraycopy(commandIds, 0, fCommandIds, 0, commandIds.length);
+ }
+
+ /**
+ * Installs the receiver on <code>viewer</code> and arms it. After this call returns, any
+ * registered listeners will be notified if a compound edit ends.
+ *
+ * @param viewer the viewer to install on
+ */
+ public void arm(ITextViewer viewer) {
+ disarm();
+ if (viewer == null)
+ throw new NullPointerException("editor"); //$NON-NLS-1$
+ fViewer= viewer;
+ addListeners(fViewer);
+ }
+
+ /**
+ * Disarms the receiver. After this call returns, any registered listeners will be not be
+ * notified any more until <code>install</code> is called again. Note that the listeners are
+ * not removed.
+ * <p>
+ * Note that the receiver is automatically disarmed when the end of a compound edit has
+ * been detected and before the listeners are notified.
+ * </p>
+ */
+ public void disarm() {
+ if (isInstalled()) {
+ removeListeners(fViewer);
+ fViewer= null;
+ }
+ }
+
+ private void addListeners(ITextViewer viewer) {
+ fWidgetEventSource= viewer.getTextWidget();
+ if (fWidgetEventSource != null) {
+ fWidgetEventSource.addVerifyKeyListener(fEventListener);
+ fWidgetEventSource.addMouseListener(fEventListener);
+ fWidgetEventSource.addFocusListener(fEventListener);
+ }
+
+ ICommandService commandService= (ICommandService)PlatformUI.getWorkbench().getAdapter(ICommandService.class);
+ if (commandService != null)
+ commandService.addExecutionListener(fEventListener);
+ }
+
+ private void removeListeners(ITextViewer editor) {
+ ICommandService commandService = (ICommandService)PlatformUI.getWorkbench().getAdapter(ICommandService.class);
+ if (commandService != null)
+ commandService.removeExecutionListener(fEventListener);
+
+ if (fWidgetEventSource != null) {
+ fWidgetEventSource.removeFocusListener(fEventListener);
+ fWidgetEventSource.removeMouseListener(fEventListener);
+ fWidgetEventSource.removeVerifyKeyListener(fEventListener);
+ fWidgetEventSource= null;
+ }
+ }
+
+ private boolean isInstalled() {
+ return fViewer != null;
+ }
+
+ private void fireEndCompoundEdit() {
+ disarm();
+ fListenerList.notifyListeners(fNotifier);
+ }
+
+ /**
+ * Adds a compound edit listener. Multiple registration is possible. Note that the receiver is
+ * automatically disarmed before the listeners are notified.
+ *
+ * @param listener the new listener
+ */
+ public void addCompoundListener(ICompoundEditListener listener) {
+ fListenerList.addListener(listener);
+ }
+
+ /**
+ * Removes a compound edit listener. If <code>listener</code> is registered multiple times, an
+ * arbitrary instance is removed. If <code>listener</code> is not currently registered,
+ * nothing happens.
+ *
+ * @param listener the listener to be removed.
+ */
+ public void removeCompoundListener(ICompoundEditListener listener) {
+ fListenerList.removeListener(listener);
+ }
+
+}

Back to the top