blob: 33f031166721e2f63a7037acc7cffa26ee1c7acb [file] [log] [blame]
david_williamscfdb2cd2004-11-11 08:37:49 +00001/*******************************************************************************
amywuecebb042007-04-10 20:07:35 +00002 * Copyright (c) 2001, 2005 IBM Corporation and others.
david_williamscfdb2cd2004-11-11 08:37:49 +00003 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
amywuecebb042007-04-10 20:07:35 +00007 *
david_williamscfdb2cd2004-11-11 08:37:49 +00008 * Contributors:
9 * IBM Corporation - initial API and implementation
10 * Jens Lukowski/Innoopract - initial renaming/restructuring
11 *
12 *******************************************************************************/
pavery0f11a862005-03-29 21:14:36 +000013package org.eclipse.wst.sse.ui.internal;
david_williamscfdb2cd2004-11-11 08:37:49 +000014
nitind1e30e012004-11-16 17:01:35 +000015import org.eclipse.core.runtime.IProgressMonitor;
16import org.eclipse.core.runtime.IStatus;
17import org.eclipse.core.runtime.Status;
18import org.eclipse.core.runtime.jobs.Job;
david_williamscfdb2cd2004-11-11 08:37:49 +000019import org.eclipse.swt.SWT;
20import org.eclipse.swt.custom.StyledText;
21import org.eclipse.swt.events.KeyEvent;
22import org.eclipse.swt.events.KeyListener;
23import org.eclipse.swt.events.MouseEvent;
24import org.eclipse.swt.events.MouseListener;
david_williamscfdb2cd2004-11-11 08:37:49 +000025import org.eclipse.swt.widgets.Display;
26import org.eclipse.swt.widgets.Event;
27import org.eclipse.swt.widgets.Listener;
david_williams2aecf082005-04-13 05:03:21 +000028import org.eclipse.wst.sse.core.internal.util.Debug;
29import org.eclipse.wst.sse.core.internal.util.Utilities;
david_williamsf3680f02005-04-13 22:43:54 +000030import org.eclipse.wst.sse.ui.internal.view.events.CaretEvent;
31import org.eclipse.wst.sse.ui.internal.view.events.ICaretListener;
david_williamscfdb2cd2004-11-11 08:37:49 +000032
david_williamscfdb2cd2004-11-11 08:37:49 +000033/**
34 * Has the responsibility of listening for key events, and mouse events,
35 * deciding if the caret has moved (without a text change), and if so, will
36 * notify CaretListeners that the caret has moved. Objects which are
37 * interested in ALL caret postion changes will also have to listen for
38 * textChanged events.
nitind0d5b3412005-09-27 21:36:16 +000039 *
40 * @deprecated - use base selection notification
david_williamscfdb2cd2004-11-11 08:37:49 +000041 */
nitind1e30e012004-11-16 17:01:35 +000042public class CaretMediator implements Listener {
david_williamscfdb2cd2004-11-11 08:37:49 +000043
nitind1e30e012004-11-16 17:01:35 +000044 class CaretMediatorListener implements KeyListener, MouseListener {
david_williamscfdb2cd2004-11-11 08:37:49 +000045 public void keyPressed(KeyEvent e) {
46 internalKeyPressed(e);
47 }
48
49 public void keyReleased(KeyEvent e) {
50 internalKeyReleased(e);
51 }
52
53 public void mouseDoubleClick(MouseEvent e) {
david_williamscfdb2cd2004-11-11 08:37:49 +000054 }
55
56 public void mouseDown(MouseEvent e) {
david_williamscfdb2cd2004-11-11 08:37:49 +000057 internalMouseDown(e);
58 }
59
60 public void mouseUp(MouseEvent e) {
61 internalMouseUp(e);
62 }
david_williamscfdb2cd2004-11-11 08:37:49 +000063 }
64
nitind1e30e012004-11-16 17:01:35 +000065 class RefreshDelayJob extends Job {
66 private int fDelay = 0;
67 RefreshDelayJob(int delay) {
david_williamsb9da93e2005-04-13 02:38:05 +000068 super(SSEUIMessages.caret_update); //$NON-NLS-1$
pavery1120ce82004-11-23 20:07:36 +000069 setSystem(true);
nitind1e30e012004-11-16 17:01:35 +000070 fDelay = delay;
david_williamscfdb2cd2004-11-11 08:37:49 +000071 }
72
73 /**
nitind1e30e012004-11-16 17:01:35 +000074 * Setup a delayed CaretEvent firing
david_williamscfdb2cd2004-11-11 08:37:49 +000075 */
nitind1e30e012004-11-16 17:01:35 +000076 void touch() {
77 cancel();
78 schedule(fDelay);
david_williamscfdb2cd2004-11-11 08:37:49 +000079 }
80
nitind1e30e012004-11-16 17:01:35 +000081 protected IStatus run(IProgressMonitor monitor) {
82 handleEvent(null);
83 return Status.OK_STATUS;
david_williamscfdb2cd2004-11-11 08:37:49 +000084 }
85 }
nitind1e30e012004-11-16 17:01:35 +000086
87 RefreshDelayJob fDelayer = null;
88 private static final int DELAY = 300;
david_williamscfdb2cd2004-11-11 08:37:49 +000089
david_williamscfdb2cd2004-11-11 08:37:49 +000090 /** used just for debug print outs */
91 private long endTime;
nitind1e30e012004-11-16 17:01:35 +000092 private long startTime;
david_williamscfdb2cd2004-11-11 08:37:49 +000093
94 protected ICaretListener[] fCaretListeners;
95 protected CaretMediatorListener internalListener;
david_williamscfdb2cd2004-11-11 08:37:49 +000096 protected StyledText textWidget;
david_williamscfdb2cd2004-11-11 08:37:49 +000097
98 /**
99 * CaretMediator constructor comment.
100 */
101 public CaretMediator() {
102 super();
103 }
104
105 /**
106 * CaretMediator constructor comment. Must always provide the widget its
107 * supposed to listen to.
108 */
nitind1e30e012004-11-16 17:01:35 +0000109 public CaretMediator(StyledText styledTextWidget) {
david_williamscfdb2cd2004-11-11 08:37:49 +0000110 this();
nitind1e30e012004-11-16 17:01:35 +0000111 setTextWidget(styledTextWidget);
david_williamscfdb2cd2004-11-11 08:37:49 +0000112 }
113
114 public synchronized void addCaretListener(ICaretListener listener) {
david_williamscfdb2cd2004-11-11 08:37:49 +0000115 if (Debug.debugStructuredDocument) {
116 System.out.println("CaretMediator::addCaretListener. Request to add an instance of " + listener.getClass() + " as a listener on caretlistner.");//$NON-NLS-2$//$NON-NLS-1$
117 }
118 // make sure listener is not already in listening array
119 // (and if it is, print a warning to aid debugging, if needed)
120
121 if (Utilities.contains(fCaretListeners, listener)) {
122 if (Debug.displayWarnings) {
123 System.out.println("CaretMediator::addCaretListener. listener " + listener + " was added more than once. ");//$NON-NLS-2$//$NON-NLS-1$
124 }
125 } else {
126 if (Debug.debugStructuredDocument) {
127 System.out.println("CaretMediator::addCaretListener. Adding an instance of " + listener.getClass() + " as a listener on caret mediator.");//$NON-NLS-2$//$NON-NLS-1$
128 }
129 int oldSize = 0;
130 if (fCaretListeners != null) {
131 // normally won't be null, but we need to be sure, for first
132 // time through
133 oldSize = fCaretListeners.length;
134 }
135 int newSize = oldSize + 1;
136 ICaretListener[] newListeners = new ICaretListener[newSize];
137 if (fCaretListeners != null) {
138 System.arraycopy(fCaretListeners, 0, newListeners, 0, oldSize);
139 }
140 // add listener to last position
141 newListeners[newSize - 1] = listener;
142 //
143 // now switch new for old
144 fCaretListeners = newListeners;
145
146 }
147 }
148
149 protected void fireCaretEvent(CaretEvent event) {
150 if (fCaretListeners != null) {
151 // we must assign listeners to local variable to be thread safe,
152 // since the add and remove listner methods
153 // can change this object's actual instance of the listener array
154 // from another thread
155 // (and since object assignment is atomic, we don't need to
156 // synchronize
157 ICaretListener[] holdListeners = fCaretListeners;
158 //
159 for (int i = 0; i < holdListeners.length; i++) {
160 holdListeners[i].caretMoved(event);
david_williamscfdb2cd2004-11-11 08:37:49 +0000161 }
162 }
163 }
164
165 public void handleEvent(Event e) {
166 Display display = null;
david_williamscfdb2cd2004-11-11 08:37:49 +0000167
168 if (Debug.debugCaretMediator) {
169 endTime = System.currentTimeMillis();
170 System.out.println("Timer fired: " + (endTime - startTime)); //$NON-NLS-1$
171 }
172
173 // check if 'okToUse'
174 if (textWidget != null && !textWidget.isDisposed()) {
175 display = textWidget.getDisplay();
176 if ((display != null) && (!display.isDisposed())) {
177 display.asyncExec(new Runnable() {
178 public void run() {
179 if (textWidget != null && !textWidget.isDisposed()) {
180 fireCaretEvent(new CaretEvent(textWidget, textWidget.getCaretOffset()));
181 }
182 }
183 });
184 }
185 }
186 }
187
188 protected void internalKeyPressed(KeyEvent e) {
nitind1e30e012004-11-16 17:01:35 +0000189 fDelayer.cancel();
david_williamscfdb2cd2004-11-11 08:37:49 +0000190 }
191
192 protected void internalKeyReleased(KeyEvent e) {
193 switch (e.keyCode) {
194 case SWT.ARROW_DOWN :
195 case SWT.ARROW_UP :
196 case SWT.ARROW_LEFT :
197 case SWT.ARROW_RIGHT :
198 case SWT.HOME :
199 case SWT.END :
200 case SWT.PAGE_DOWN :
201 case SWT.PAGE_UP : {
nitind1e30e012004-11-16 17:01:35 +0000202 fDelayer.touch();
david_williamscfdb2cd2004-11-11 08:37:49 +0000203 break;
204 }
205 default : {
206 // always update cursor postion, even during normal typing
207 // (the logic may look funny, since we always to the same
208 // thing, but we haven't always done the same thing, so I
209 // wanted to leave that fact documented via code.)
nitind1e30e012004-11-16 17:01:35 +0000210 fDelayer.touch();
david_williamscfdb2cd2004-11-11 08:37:49 +0000211 }
212 }
213 }
214
215 protected void internalMouseDown(MouseEvent e) {
nitind1e30e012004-11-16 17:01:35 +0000216 fDelayer.cancel();
david_williamscfdb2cd2004-11-11 08:37:49 +0000217 }
218
219 protected void internalMouseUp(MouseEvent e) {
220 // Note, even during a swipe select, when the mouse button goes up,
221 // and the widget is
222 // queried for the current caret postion, it always returns the
223 // beginning of the selection,
224 // which is desirable (at least for the known use of this feature,
225 // which is to signal
226 // that the property sheet can update itself.
nitind1e30e012004-11-16 17:01:35 +0000227 fDelayer.touch();
david_williamscfdb2cd2004-11-11 08:37:49 +0000228 }
229
230 public void release() {
nitind1e30e012004-11-16 17:01:35 +0000231 fDelayer.cancel();
david_williamscfdb2cd2004-11-11 08:37:49 +0000232 if (textWidget != null && !textWidget.isDisposed()) {
233 textWidget.removeKeyListener(internalListener);
234 textWidget.removeMouseListener(internalListener);
david_williamscfdb2cd2004-11-11 08:37:49 +0000235 textWidget = null;
236 }
david_williamscfdb2cd2004-11-11 08:37:49 +0000237 }
238
239 public synchronized void removeCaretListener(ICaretListener listener) {
david_williamscfdb2cd2004-11-11 08:37:49 +0000240 if ((fCaretListeners != null) && (listener != null)) {
241 // if its not in the listeners, we'll ignore the request
242 if (Utilities.contains(fCaretListeners, listener)) {
243 int oldSize = fCaretListeners.length;
244 int newSize = oldSize - 1;
245 ICaretListener[] newListeners = new ICaretListener[newSize];
246 int index = 0;
247 for (int i = 0; i < oldSize; i++) {
248 if (fCaretListeners[i] == listener) { // ignore
249 } else {
250 // copy old to new if its not the one we are removing
251 newListeners[index++] = fCaretListeners[i];
252 }
253 }
254 // now that we have a new array, let's switch it for the old
255 // one
256 fCaretListeners = newListeners;
257 }
258 }
259 }
260
261 public void setTextWidget(StyledText newTextWidget) {
nitind1e30e012004-11-16 17:01:35 +0000262 if(fDelayer == null) {
263 fDelayer = new RefreshDelayJob(DELAY);
david_williamscfdb2cd2004-11-11 08:37:49 +0000264 }
265
nitind1e30e012004-11-16 17:01:35 +0000266 // unhook from previous, if any
267 if (this.textWidget != null) {
268 fDelayer.cancel();
269 this.textWidget.removeKeyListener(internalListener);
270 this.textWidget.removeMouseListener(internalListener);
271 }
272
david_williamscfdb2cd2004-11-11 08:37:49 +0000273 this.textWidget = newTextWidget;
274
275 if (internalListener == null) {
276 internalListener = new CaretMediatorListener();
277 }
278
279 if (this.textWidget != null) {
280 this.textWidget.addKeyListener(internalListener);
281 this.textWidget.addMouseListener(internalListener);
david_williamscfdb2cd2004-11-11 08:37:49 +0000282 }
david_williamscfdb2cd2004-11-11 08:37:49 +0000283 }
284}