| /******************************************************************************* |
| * Copyright (c) 2001, 2004 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| * Jens Lukowski/Innoopract - initial renaming/restructuring |
| * |
| *******************************************************************************/ |
| package org.eclipse.wst.sse.ui.internal; |
| |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.core.runtime.jobs.Job; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.custom.StyledText; |
| import org.eclipse.swt.events.KeyEvent; |
| import org.eclipse.swt.events.KeyListener; |
| import org.eclipse.swt.events.MouseEvent; |
| import org.eclipse.swt.events.MouseListener; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Event; |
| import org.eclipse.swt.widgets.Listener; |
| import org.eclipse.wst.sse.core.internal.util.Debug; |
| import org.eclipse.wst.sse.core.internal.util.Utilities; |
| import org.eclipse.wst.sse.ui.internal.view.events.CaretEvent; |
| import org.eclipse.wst.sse.ui.internal.view.events.ICaretListener; |
| |
| /** |
| * Has the responsibility of listening for key events, and mouse events, |
| * deciding if the caret has moved (without a text change), and if so, will |
| * notify CaretListeners that the caret has moved. Objects which are |
| * interested in ALL caret postion changes will also have to listen for |
| * textChanged events. |
| * |
| * @deprecated - use base selection notification |
| */ |
| public class CaretMediator implements Listener { |
| |
| class CaretMediatorListener implements KeyListener, MouseListener { |
| public void keyPressed(KeyEvent e) { |
| internalKeyPressed(e); |
| } |
| |
| public void keyReleased(KeyEvent e) { |
| internalKeyReleased(e); |
| } |
| |
| public void mouseDoubleClick(MouseEvent e) { |
| } |
| |
| public void mouseDown(MouseEvent e) { |
| internalMouseDown(e); |
| } |
| |
| public void mouseUp(MouseEvent e) { |
| internalMouseUp(e); |
| } |
| } |
| |
| class RefreshDelayJob extends Job { |
| private int fDelay = 0; |
| RefreshDelayJob(int delay) { |
| super(SSEUIMessages.caret_update); //$NON-NLS-1$ |
| setSystem(true); |
| fDelay = delay; |
| } |
| |
| /** |
| * Setup a delayed CaretEvent firing |
| */ |
| void touch() { |
| cancel(); |
| schedule(fDelay); |
| } |
| |
| protected IStatus run(IProgressMonitor monitor) { |
| handleEvent(null); |
| return Status.OK_STATUS; |
| } |
| } |
| |
| RefreshDelayJob fDelayer = null; |
| private static final int DELAY = 300; |
| |
| /** used just for debug print outs */ |
| private long endTime; |
| private long startTime; |
| |
| protected ICaretListener[] fCaretListeners; |
| protected CaretMediatorListener internalListener; |
| protected StyledText textWidget; |
| |
| /** |
| * CaretMediator constructor comment. |
| */ |
| public CaretMediator() { |
| super(); |
| } |
| |
| /** |
| * CaretMediator constructor comment. Must always provide the widget its |
| * supposed to listen to. |
| */ |
| public CaretMediator(StyledText styledTextWidget) { |
| this(); |
| setTextWidget(styledTextWidget); |
| } |
| |
| public synchronized void addCaretListener(ICaretListener listener) { |
| if (Debug.debugStructuredDocument) { |
| System.out.println("CaretMediator::addCaretListener. Request to add an instance of " + listener.getClass() + " as a listener on caretlistner.");//$NON-NLS-2$//$NON-NLS-1$ |
| } |
| // make sure listener is not already in listening array |
| // (and if it is, print a warning to aid debugging, if needed) |
| |
| if (Utilities.contains(fCaretListeners, listener)) { |
| if (Debug.displayWarnings) { |
| System.out.println("CaretMediator::addCaretListener. listener " + listener + " was added more than once. ");//$NON-NLS-2$//$NON-NLS-1$ |
| } |
| } else { |
| if (Debug.debugStructuredDocument) { |
| System.out.println("CaretMediator::addCaretListener. Adding an instance of " + listener.getClass() + " as a listener on caret mediator.");//$NON-NLS-2$//$NON-NLS-1$ |
| } |
| int oldSize = 0; |
| if (fCaretListeners != null) { |
| // normally won't be null, but we need to be sure, for first |
| // time through |
| oldSize = fCaretListeners.length; |
| } |
| int newSize = oldSize + 1; |
| ICaretListener[] newListeners = new ICaretListener[newSize]; |
| if (fCaretListeners != null) { |
| System.arraycopy(fCaretListeners, 0, newListeners, 0, oldSize); |
| } |
| // add listener to last position |
| newListeners[newSize - 1] = listener; |
| // |
| // now switch new for old |
| fCaretListeners = newListeners; |
| |
| } |
| } |
| |
| protected void fireCaretEvent(CaretEvent event) { |
| if (fCaretListeners != null) { |
| // we must assign listeners to local variable to be thread safe, |
| // since the add and remove listner methods |
| // can change this object's actual instance of the listener array |
| // from another thread |
| // (and since object assignment is atomic, we don't need to |
| // synchronize |
| ICaretListener[] holdListeners = fCaretListeners; |
| // |
| for (int i = 0; i < holdListeners.length; i++) { |
| holdListeners[i].caretMoved(event); |
| } |
| } |
| } |
| |
| public void handleEvent(Event e) { |
| Display display = null; |
| |
| if (Debug.debugCaretMediator) { |
| endTime = System.currentTimeMillis(); |
| System.out.println("Timer fired: " + (endTime - startTime)); //$NON-NLS-1$ |
| } |
| |
| // check if 'okToUse' |
| if (textWidget != null && !textWidget.isDisposed()) { |
| display = textWidget.getDisplay(); |
| if ((display != null) && (!display.isDisposed())) { |
| display.asyncExec(new Runnable() { |
| public void run() { |
| if (textWidget != null && !textWidget.isDisposed()) { |
| fireCaretEvent(new CaretEvent(textWidget, textWidget.getCaretOffset())); |
| } |
| } |
| }); |
| } |
| } |
| } |
| |
| protected void internalKeyPressed(KeyEvent e) { |
| fDelayer.cancel(); |
| } |
| |
| protected void internalKeyReleased(KeyEvent e) { |
| switch (e.keyCode) { |
| case SWT.ARROW_DOWN : |
| case SWT.ARROW_UP : |
| case SWT.ARROW_LEFT : |
| case SWT.ARROW_RIGHT : |
| case SWT.HOME : |
| case SWT.END : |
| case SWT.PAGE_DOWN : |
| case SWT.PAGE_UP : { |
| fDelayer.touch(); |
| break; |
| } |
| default : { |
| // always update cursor postion, even during normal typing |
| // (the logic may look funny, since we always to the same |
| // thing, but we haven't always done the same thing, so I |
| // wanted to leave that fact documented via code.) |
| fDelayer.touch(); |
| } |
| } |
| } |
| |
| protected void internalMouseDown(MouseEvent e) { |
| fDelayer.cancel(); |
| } |
| |
| protected void internalMouseUp(MouseEvent e) { |
| // Note, even during a swipe select, when the mouse button goes up, |
| // and the widget is |
| // queried for the current caret postion, it always returns the |
| // beginning of the selection, |
| // which is desirable (at least for the known use of this feature, |
| // which is to signal |
| // that the property sheet can update itself. |
| fDelayer.touch(); |
| } |
| |
| public void release() { |
| fDelayer.cancel(); |
| if (textWidget != null && !textWidget.isDisposed()) { |
| textWidget.removeKeyListener(internalListener); |
| textWidget.removeMouseListener(internalListener); |
| textWidget = null; |
| } |
| } |
| |
| public synchronized void removeCaretListener(ICaretListener listener) { |
| if ((fCaretListeners != null) && (listener != null)) { |
| // if its not in the listeners, we'll ignore the request |
| if (Utilities.contains(fCaretListeners, listener)) { |
| int oldSize = fCaretListeners.length; |
| int newSize = oldSize - 1; |
| ICaretListener[] newListeners = new ICaretListener[newSize]; |
| int index = 0; |
| for (int i = 0; i < oldSize; i++) { |
| if (fCaretListeners[i] == listener) { // ignore |
| } else { |
| // copy old to new if its not the one we are removing |
| newListeners[index++] = fCaretListeners[i]; |
| } |
| } |
| // now that we have a new array, let's switch it for the old |
| // one |
| fCaretListeners = newListeners; |
| } |
| } |
| } |
| |
| public void setTextWidget(StyledText newTextWidget) { |
| if(fDelayer == null) { |
| fDelayer = new RefreshDelayJob(DELAY); |
| } |
| |
| // unhook from previous, if any |
| if (this.textWidget != null) { |
| fDelayer.cancel(); |
| this.textWidget.removeKeyListener(internalListener); |
| this.textWidget.removeMouseListener(internalListener); |
| } |
| |
| this.textWidget = newTextWidget; |
| |
| if (internalListener == null) { |
| internalListener = new CaretMediatorListener(); |
| } |
| |
| if (this.textWidget != null) { |
| this.textWidget.addKeyListener(internalListener); |
| this.textWidget.addMouseListener(internalListener); |
| } |
| } |
| } |