Mercurial > projects > dwt-addons
annotate dwtx/jface/internal/text/StickyHoverManager.d @ 133:7d818bd32d63
Fix ctors to this with gvim regexp
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Sun, 24 Aug 2008 01:29:22 +0200 |
parents | c4fb132a086c |
children | 51e6e63f930e |
rev | line source |
---|---|
129 | 1 /******************************************************************************* |
2 * Copyright (c) 2007, 2008 IBM Corporation and others. | |
3 * 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 | |
7 * | |
8 * Contributors: | |
9 * IBM Corporation - initial API and implementation | |
10 * Port to the D programming language: | |
11 * Frank Benoit <benoit@tionex.de> | |
12 *******************************************************************************/ | |
13 module dwtx.jface.internal.text.StickyHoverManager; | |
14 | |
131 | 15 import dwtx.jface.internal.text.NonDeletingPositionUpdater; // packageimport |
16 import dwtx.jface.internal.text.InternalAccessor; // packageimport | |
17 import dwtx.jface.internal.text.InformationControlReplacer; // packageimport | |
18 import dwtx.jface.internal.text.TableOwnerDrawSupport; // packageimport | |
19 import dwtx.jface.internal.text.DelayedInputChangeListener; // packageimport | |
20 | |
21 | |
129 | 22 import dwt.dwthelper.utils; |
23 | |
24 | |
25 | |
26 import dwt.DWT; | |
27 import dwt.events.ControlEvent; | |
28 import dwt.events.ControlListener; | |
29 import dwt.events.FocusEvent; | |
30 import dwt.events.FocusListener; | |
31 import dwt.events.KeyEvent; | |
32 import dwt.events.KeyListener; | |
33 import dwt.events.MouseEvent; | |
34 import dwt.events.MouseListener; | |
35 import dwt.graphics.Point; | |
36 import dwt.graphics.Rectangle; | |
37 import dwt.widgets.Control; | |
38 import dwt.widgets.Display; | |
39 import dwt.widgets.Event; | |
40 import dwt.widgets.Listener; | |
41 import dwtx.jface.text.IInformationControl; | |
42 import dwtx.jface.text.IInformationControlExtension3; | |
43 import dwtx.jface.text.IInformationControlExtension5; | |
44 import dwtx.jface.text.IViewportListener; | |
45 import dwtx.jface.text.IWidgetTokenKeeper; | |
46 import dwtx.jface.text.IWidgetTokenKeeperExtension; | |
47 import dwtx.jface.text.IWidgetTokenOwner; | |
48 import dwtx.jface.text.TextViewer; | |
49 import dwtx.jface.util.Geometry; | |
50 | |
51 | |
52 /** | |
53 * Implements a sticky hover control, i.e. a control that replaces a hover | |
54 * with an enriched and focusable control. | |
55 * <p> | |
56 * The information control is made visible on request by calling | |
57 * {@link #showInformationControl(Rectangle)}. | |
58 * </p> | |
59 * <p> | |
60 * Clients usually instantiate and configure this class before using it. The configuration | |
61 * must be consistent: This means the used {@link dwtx.jface.text.IInformationControlCreator} | |
62 * must create an information control expecting information in the same format the configured | |
63 * {@link dwtx.jface.text.information.IInformationProvider}s use to encode the information they provide. | |
64 * </p> | |
65 * | |
66 * @since 3.4 | |
67 */ | |
68 public class StickyHoverManager : InformationControlReplacer , IWidgetTokenKeeper, IWidgetTokenKeeperExtension { | |
69 | |
70 /** | |
71 * Priority of the info controls managed by this sticky hover manager. | |
72 * <p> | |
73 * Note: Only applicable when info control does not have focus. | |
74 * -5 as value has been chosen in order to be beaten by the hovers of TextViewerHoverManager. | |
75 * </p> | |
76 */ | |
77 private static final int WIDGET_PRIORITY= -5; | |
78 | |
79 | |
80 /** | |
81 * Internal information control closer. Listens to several events issued by its subject control | |
82 * and closes the information control when necessary. | |
83 */ | |
84 class Closer : IInformationControlCloser, ControlListener, MouseListener, IViewportListener, KeyListener, FocusListener, Listener { | |
85 //TODO: Catch 'Esc' key in fInformationControlToClose: Don't dispose, just hideInformationControl(). | |
86 // This would allow to reuse the information control also when the user explicitly closes it. | |
87 | |
88 //TODO: if subject control is a Scrollable, should add selection listeners to both scroll bars | |
89 // (and remove the ViewPortListener, which only listens to vertical scrolling) | |
90 | |
91 /** The subject control. */ | |
92 private Control fSubjectControl; | |
93 /** Indicates whether this closer is active. */ | |
94 private bool fIsActive= false; | |
95 /** The display. */ | |
96 private Display fDisplay; | |
97 | |
98 /* | |
99 * @see IInformationControlCloser#setSubjectControl(Control) | |
100 */ | |
101 public void setSubjectControl(Control control) { | |
102 fSubjectControl= control; | |
103 } | |
104 | |
105 /* | |
106 * @see IInformationControlCloser#setInformationControl(IInformationControl) | |
107 */ | |
108 public void setInformationControl(IInformationControl control) { | |
109 // NOTE: we use getCurrentInformationControl2() from the outer class | |
110 } | |
111 | |
112 /* | |
113 * @see IInformationControlCloser#start(Rectangle) | |
114 */ | |
115 public void start(Rectangle informationArea) { | |
116 | |
117 if (fIsActive) | |
118 return; | |
119 fIsActive= true; | |
120 | |
121 if (fSubjectControl !is null && !fSubjectControl.isDisposed()) { | |
122 fSubjectControl.addControlListener(this); | |
123 fSubjectControl.addMouseListener(this); | |
124 fSubjectControl.addKeyListener(this); | |
125 } | |
126 | |
127 fTextViewer.addViewportListener(this); | |
128 | |
129 IInformationControl fInformationControlToClose= getCurrentInformationControl2(); | |
130 if (fInformationControlToClose !is null) | |
131 fInformationControlToClose.addFocusListener(this); | |
132 | |
133 fDisplay= fSubjectControl.getDisplay(); | |
134 if (!fDisplay.isDisposed()) { | |
135 fDisplay.addFilter(DWT.MouseMove, this); | |
136 fDisplay.addFilter(DWT.FocusOut, this); | |
137 } | |
138 } | |
139 | |
140 /* | |
141 * @see IInformationControlCloser#stop() | |
142 */ | |
143 public void stop() { | |
144 | |
145 if (!fIsActive) | |
146 return; | |
147 fIsActive= false; | |
148 | |
149 fTextViewer.removeViewportListener(this); | |
150 | |
151 if (fSubjectControl !is null && !fSubjectControl.isDisposed()) { | |
152 fSubjectControl.removeControlListener(this); | |
153 fSubjectControl.removeMouseListener(this); | |
154 fSubjectControl.removeKeyListener(this); | |
155 } | |
156 | |
157 IInformationControl fInformationControlToClose= getCurrentInformationControl2(); | |
158 if (fInformationControlToClose !is null) | |
159 fInformationControlToClose.removeFocusListener(this); | |
160 | |
161 if (fDisplay !is null && !fDisplay.isDisposed()) { | |
162 fDisplay.removeFilter(DWT.MouseMove, this); | |
163 fDisplay.removeFilter(DWT.FocusOut, this); | |
164 } | |
165 | |
166 fDisplay= null; | |
167 } | |
168 | |
169 /* | |
170 * @see ControlListener#controlResized(ControlEvent) | |
171 */ | |
172 public void controlResized(ControlEvent e) { | |
173 hideInformationControl(); | |
174 } | |
175 | |
176 /* | |
177 * @see ControlListener#controlMoved(ControlEvent) | |
178 */ | |
179 public void controlMoved(ControlEvent e) { | |
180 hideInformationControl(); | |
181 } | |
182 | |
183 /* | |
184 * @see MouseListener#mouseDown(MouseEvent) | |
185 */ | |
186 public void mouseDown(MouseEvent e) { | |
187 hideInformationControl(); | |
188 } | |
189 | |
190 /* | |
191 * @see MouseListener#mouseUp(MouseEvent) | |
192 */ | |
193 public void mouseUp(MouseEvent e) { | |
194 } | |
195 | |
196 /* | |
197 * @see MouseListener#mouseDoubleClick(MouseEvent) | |
198 */ | |
199 public void mouseDoubleClick(MouseEvent e) { | |
200 hideInformationControl(); | |
201 } | |
202 | |
203 /* | |
204 * @see IViewportListenerListener#viewportChanged(int) | |
205 */ | |
206 public void viewportChanged(int topIndex) { | |
207 hideInformationControl(); | |
208 } | |
209 | |
210 /* | |
211 * @see KeyListener#keyPressed(KeyEvent) | |
212 */ | |
213 public void keyPressed(KeyEvent e) { | |
214 hideInformationControl(); | |
215 } | |
216 | |
217 /* | |
218 * @see KeyListener#keyReleased(KeyEvent) | |
219 */ | |
220 public void keyReleased(KeyEvent e) { | |
221 } | |
222 | |
223 /* | |
224 * @see dwt.events.FocusListener#focusGained(dwt.events.FocusEvent) | |
225 */ | |
226 public void focusGained(FocusEvent e) { | |
227 } | |
228 | |
229 /* | |
230 * @see dwt.events.FocusListener#focusLost(dwt.events.FocusEvent) | |
231 */ | |
232 public void focusLost(FocusEvent e) { | |
233 if (DEBUG) System.out.println("StickyHoverManager.Closer.focusLost(): " + e); //$NON-NLS-1$ | |
234 Display d= fSubjectControl.getDisplay(); | |
235 d.asyncExec(new Runnable() { | |
236 // Without the asyncExec, mouse clicks to the workbench window are swallowed. | |
237 public void run() { | |
238 hideInformationControl(); | |
239 } | |
240 }); | |
241 } | |
242 | |
243 /* | |
244 * @see dwt.widgets.Listener#handleEvent(dwt.widgets.Event) | |
245 */ | |
246 public void handleEvent(Event event) { | |
247 if (event.type is DWT.MouseMove) { | |
248 if (!(event.widget instanceof Control) || event.widget.isDisposed()) | |
249 return; | |
250 | |
251 IInformationControl infoControl= getCurrentInformationControl2(); | |
252 if (infoControl !is null && !infoControl.isFocusControl() && infoControl instanceof IInformationControlExtension3) { | |
253 // if (DEBUG) System.out.println("StickyHoverManager.Closer.handleEvent(): activeShell= " + fDisplay.getActiveShell()); //$NON-NLS-1$ | |
254 IInformationControlExtension3 iControl3= (IInformationControlExtension3) infoControl; | |
255 Rectangle controlBounds= iControl3.getBounds(); | |
256 if (controlBounds !is null) { | |
257 Point mouseLoc= event.display.map((Control) event.widget, null, event.x, event.y); | |
258 int margin= getKeepUpMargin(); | |
259 Geometry.expand(controlBounds, margin, margin, margin, margin); | |
260 if (!controlBounds.contains(mouseLoc)) { | |
261 hideInformationControl(); | |
262 } | |
263 } | |
264 | |
265 } else { | |
266 /* | |
267 * TODO: need better understanding of why/if this is needed. | |
268 * Looks like the same panic code we have in dwtx.jface.text.AbstractHoverInformationControlManager.Closer.handleMouseMove(Event) | |
269 */ | |
270 if (fDisplay !is null && !fDisplay.isDisposed()) | |
271 fDisplay.removeFilter(DWT.MouseMove, this); | |
272 } | |
273 | |
274 } else if (event.type is DWT.FocusOut) { | |
275 if (DEBUG) System.out.println("StickyHoverManager.Closer.handleEvent(): focusOut: " + event); //$NON-NLS-1$ | |
276 IInformationControl iControl= getCurrentInformationControl2(); | |
277 if (iControl !is null && ! iControl.isFocusControl()) | |
278 hideInformationControl(); | |
279 } | |
280 } | |
281 } | |
282 | |
283 | |
284 private final TextViewer fTextViewer; | |
285 | |
286 | |
287 /** | |
288 * Creates a new sticky hover manager. | |
289 * | |
290 * @param textViewer the text viewer | |
291 */ | |
133
7d818bd32d63
Fix ctors to this with gvim regexp
Frank Benoit <benoit@tionex.de>
parents:
131
diff
changeset
|
292 public this(TextViewer textViewer) { |
129 | 293 super(new DefaultInformationControlCreator()); |
294 | |
295 fTextViewer= textViewer; | |
296 setCloser(new Closer()); | |
297 | |
298 install(fTextViewer.getTextWidget()); | |
299 } | |
300 | |
301 /* | |
302 * @see AbstractInformationControlManager#showInformationControl(Rectangle) | |
303 */ | |
304 protected void showInformationControl(Rectangle subjectArea) { | |
305 if (fTextViewer !is null && fTextViewer.requestWidgetToken(this, WIDGET_PRIORITY)) | |
306 super.showInformationControl(subjectArea); | |
307 else | |
308 if (DEBUG) | |
309 System.out.println("cancelled StickyHoverManager.showInformationControl(..): did not get widget token (with prio)"); //$NON-NLS-1$ | |
310 } | |
311 | |
312 /* | |
313 * @see AbstractInformationControlManager#hideInformationControl() | |
314 */ | |
315 public void hideInformationControl() { | |
316 try { | |
317 super.hideInformationControl(); | |
318 } finally { | |
319 if (fTextViewer !is null) | |
320 fTextViewer.releaseWidgetToken(this); | |
321 } | |
322 } | |
323 | |
324 /* | |
325 * @see AbstractInformationControlManager#handleInformationControlDisposed() | |
326 */ | |
327 protected void handleInformationControlDisposed() { | |
328 try { | |
329 super.handleInformationControlDisposed(); | |
330 } finally { | |
331 if (fTextViewer !is null) | |
332 fTextViewer.releaseWidgetToken(this); | |
333 } | |
334 } | |
335 | |
336 /* | |
337 * @see dwtx.jface.text.IWidgetTokenKeeper#requestWidgetToken(IWidgetTokenOwner) | |
338 */ | |
339 public bool requestWidgetToken(IWidgetTokenOwner owner) { | |
340 hideInformationControl(); | |
341 if (DEBUG) | |
342 System.out.println("StickyHoverManager gave up widget token (no prio)"); //$NON-NLS-1$ | |
343 return true; | |
344 } | |
345 | |
346 /* | |
347 * @see dwtx.jface.text.IWidgetTokenKeeperExtension#requestWidgetToken(dwtx.jface.text.IWidgetTokenOwner, int) | |
348 */ | |
349 public bool requestWidgetToken(IWidgetTokenOwner owner, int priority) { | |
350 if (getCurrentInformationControl2() !is null) { | |
351 if (getCurrentInformationControl2().isFocusControl()) { | |
352 if (DEBUG) | |
353 System.out.println("StickyHoverManager kept widget token (focused)"); //$NON-NLS-1$ | |
354 return false; | |
355 } else if (priority > WIDGET_PRIORITY) { | |
356 hideInformationControl(); | |
357 if (DEBUG) | |
358 System.out.println("StickyHoverManager gave up widget token (prio)"); //$NON-NLS-1$ | |
359 return true; | |
360 } else { | |
361 if (DEBUG) | |
362 System.out.println("StickyHoverManager kept widget token (prio)"); //$NON-NLS-1$ | |
363 return false; | |
364 } | |
365 } | |
366 if (DEBUG) | |
367 System.out.println("StickyHoverManager gave up widget token (no iControl)"); //$NON-NLS-1$ | |
368 return true; | |
369 } | |
370 | |
371 /* | |
372 * @see dwtx.jface.text.IWidgetTokenKeeperExtension#setFocus(dwtx.jface.text.IWidgetTokenOwner) | |
373 */ | |
374 public bool setFocus(IWidgetTokenOwner owner) { | |
375 IInformationControl iControl= getCurrentInformationControl2(); | |
376 if (iControl instanceof IInformationControlExtension5) { | |
377 IInformationControlExtension5 iControl5= (IInformationControlExtension5) iControl; | |
378 if (iControl5.isVisible()) { | |
379 iControl.setFocus(); | |
380 return iControl.isFocusControl(); | |
381 } | |
382 return false; | |
383 } | |
384 iControl.setFocus(); | |
385 return iControl.isFocusControl(); | |
386 } | |
387 | |
388 } |