KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jface > text > AbstractHoverInformationControlManager


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 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  *******************************************************************************/

11
12 package org.eclipse.jface.text;
13
14
15 import org.eclipse.swt.SWT;
16 import org.eclipse.swt.events.ControlEvent;
17 import org.eclipse.swt.events.ControlListener;
18 import org.eclipse.swt.events.KeyEvent;
19 import org.eclipse.swt.events.KeyListener;
20 import org.eclipse.swt.events.MouseEvent;
21 import org.eclipse.swt.events.MouseListener;
22 import org.eclipse.swt.events.MouseMoveListener;
23 import org.eclipse.swt.events.MouseTrackAdapter;
24 import org.eclipse.swt.events.MouseTrackListener;
25 import org.eclipse.swt.events.ShellAdapter;
26 import org.eclipse.swt.events.ShellEvent;
27 import org.eclipse.swt.events.ShellListener;
28 import org.eclipse.swt.graphics.Point;
29 import org.eclipse.swt.graphics.Rectangle;
30 import org.eclipse.swt.widgets.Control;
31 import org.eclipse.swt.widgets.Display;
32 import org.eclipse.swt.widgets.Event;
33 import org.eclipse.swt.widgets.Listener;
34
35 import org.eclipse.core.runtime.Assert;
36
37
38 /**
39  * An information control manager that shows information in response to mouse
40  * hover events. The mouse hover events are caught by registering a
41  * {@link org.eclipse.swt.events.MouseTrackListener} on the manager's subject
42  * control. The manager has by default an information control closer that closes
43  * the information control as soon as the mouse pointer leaves the subject area,
44  * the user presses a key, or the subject control is resized, moved, or
45  * deactivated.
46  * <p>
47  * When being activated by a mouse hover event, the manager disables itself,
48  * until the mouse leaves the subject area. Thus, the manager is usually still
49  * disabled, when the information control has already been closed by the closer.
50  *
51  * @see org.eclipse.swt.events.MouseTrackListener
52  * @since 2.0
53  */

54 abstract public class AbstractHoverInformationControlManager extends AbstractInformationControlManager {
55
56
57     /**
58      * The information control closer for the hover information. Closes the information control as
59      * soon as the mouse pointer leaves the subject area, a mouse button is pressed, the user presses a key,
60      * or the subject control is resized or moved.
61      */

62     class Closer extends MouseTrackAdapter
63         implements IInformationControlCloser, MouseListener, MouseMoveListener, ControlListener, KeyListener, ShellListener, Listener {
64
65         /** The closer's subject control */
66         private Control fSubjectControl;
67         /** The subject area */
68         private Rectangle fSubjectArea;
69         /** Indicates whether this closer is active */
70         private boolean fIsActive= false;
71         /**
72          * The cached display.
73          * @since 3.1
74          */

75         private Display fDisplay;
76
77
78         /**
79          * Creates a new information control closer.
80          */

81         public Closer() {
82         }
83
84         /*
85          * @see IInformationControlCloser#setSubjectControl(Control)
86          */

87         public void setSubjectControl(Control control) {
88             fSubjectControl= control;
89         }
90
91         /*
92          * @see IInformationControlCloser#setHoverControl(IHoverControl)
93          */

94         public void setInformationControl(IInformationControl control) {
95         }
96
97         /*
98          * @see IInformationControlCloser#start(Rectangle)
99          */

100         public void start(Rectangle subjectArea) {
101
102             if (fIsActive) return;
103             fIsActive= true;
104
105             fSubjectArea= subjectArea;
106
107             if (fSubjectControl != null && !fSubjectControl.isDisposed()) {
108                 fSubjectControl.addMouseListener(this);
109                 fSubjectControl.addMouseMoveListener(this);
110                 fSubjectControl.addMouseTrackListener(this);
111                 fSubjectControl.addControlListener(this);
112                 fSubjectControl.addKeyListener(this);
113                 fSubjectControl.getShell().addShellListener(this);
114
115                 fDisplay= fSubjectControl.getDisplay();
116                 if (!fDisplay.isDisposed()) {
117                     fDisplay.addFilter(SWT.Show, this);
118                     fDisplay.addFilter(SWT.Activate, this);
119                     fDisplay.addFilter(SWT.MouseWheel, this);
120                 }
121             }
122         }
123
124         /*
125          * @see IInformationControlCloser#stop()
126          */

127         public void stop() {
128             stop(false);
129         }
130
131         /**
132          * Stops the information control and if <code>delayRestart</code> is set
133          * allows restart only after a certain delay.
134          *
135          * @param delayRestart <code>true</code> if restart should be delayed
136          */

137         protected void stop(boolean delayRestart) {
138
139             if (!fIsActive)
140                 return;
141
142             fIsActive= false;
143
144             hideInformationControl();
145
146             if (fSubjectControl != null && !fSubjectControl.isDisposed()) {
147                 fSubjectControl.removeMouseListener(this);
148                 fSubjectControl.removeMouseMoveListener(this);
149                 fSubjectControl.removeMouseTrackListener(this);
150                 fSubjectControl.removeControlListener(this);
151                 fSubjectControl.removeKeyListener(this);
152                 fSubjectControl.getShell().removeShellListener(this);
153             }
154
155             if (fDisplay != null && !fDisplay.isDisposed()) {
156                 fDisplay.removeFilter(SWT.Show, this);
157                 fDisplay.removeFilter(SWT.Activate, this);
158                 fDisplay.removeFilter(SWT.MouseWheel, this);
159             }
160             fDisplay= null;
161         }
162
163         /*
164          * @see org.eclipse.swt.events.MouseMoveListener#mouseMove(org.eclipse.swt.events.MouseEvent)
165          */

166         public void mouseMove(MouseEvent event) {
167             if (!fSubjectArea.contains(event.x, event.y))
168                 stop();
169         }
170
171         /*
172          * @see org.eclipse.swt.events.MouseListener#mouseUp(org.eclipse.swt.events.MouseEvent)
173          */

174         public void mouseUp(MouseEvent event) {
175         }
176
177         /*
178          * @see MouseListener#mouseDown(MouseEvent)
179          */

180         public void mouseDown(MouseEvent event) {
181             stop();
182         }
183
184         /*
185          * @see MouseListener#mouseDoubleClick(MouseEvent)
186          */

187         public void mouseDoubleClick(MouseEvent event) {
188             stop();
189         }
190
191         /*
192          * @see MouseTrackAdapter#mouseExit(MouseEvent)
193          */

194         public void mouseExit(MouseEvent event) {
195             stop();
196         }
197
198         /*
199          * @see ControlListener#controlResized(ControlEvent)
200          */

201         public void controlResized(ControlEvent event) {
202             stop();
203         }
204
205         /*
206          * @see ControlListener#controlMoved(ControlEvent)
207          */

208         public void controlMoved(ControlEvent event) {
209             stop();
210         }
211
212         /*
213          * @see KeyListener#keyReleased(KeyEvent)
214          */

215         public void keyReleased(KeyEvent event) {
216         }
217
218         /*
219          * @see KeyListener#keyPressed(KeyEvent)
220          */

221         public void keyPressed(KeyEvent event) {
222             stop(true);
223         }
224
225         /*
226          * @see org.eclipse.swt.events.ShellListener#shellActivated(org.eclipse.swt.events.ShellEvent)
227          * @since 3.1
228          */

229         public void shellActivated(ShellEvent e) {
230         }
231
232         /*
233          * @see org.eclipse.swt.events.ShellListener#shellClosed(org.eclipse.swt.events.ShellEvent)
234          * @since 3.1
235          */

236         public void shellClosed(ShellEvent e) {
237         }
238
239         /*
240          * @see org.eclipse.swt.events.ShellListener#shellDeactivated(org.eclipse.swt.events.ShellEvent)
241          * @since 3.1
242          */

243         public void shellDeactivated(ShellEvent e) {
244             stop();
245         }
246
247         /*
248          * @see org.eclipse.swt.events.ShellListener#shellDeiconified(org.eclipse.swt.events.ShellEvent)
249          * @since 3.1
250          */

251         public void shellDeiconified(ShellEvent e) {
252         }
253
254         /*
255          * @see org.eclipse.swt.events.ShellListener#shellIconified(org.eclipse.swt.events.ShellEvent)
256          * @since 3.1
257          */

258         public void shellIconified(ShellEvent e) {
259         }
260
261         /*
262          * @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event)
263          * @since 3.1
264          */

265         public void handleEvent(Event event) {
266             if (event.type == SWT.Activate || event.type == SWT.Show || event.type == SWT.MouseWheel)
267                 stop();
268         }
269     }
270
271
272     /**
273      * To be installed on the manager's subject control. Serves two different purposes:
274      * <ul>
275      * <li> start function: initiates the computation of the information to be presented. This happens on
276      * receipt of a mouse hover event and disables the information control manager,
277      * <li> restart function: tracks mouse move and shell activation event to determine when the information
278      * control manager needs to be reactivated.
279      * </ul>
280      */

281     class MouseTracker extends ShellAdapter implements MouseTrackListener, MouseMoveListener {
282
283         /** Margin around the original hover event location for computing the hover area. */
284         private final static int EPSILON= 3;
285
286         /** The area in which the original hover event occurred. */
287         private Rectangle fHoverArea;
288         /** The area for which is computed information is valid. */
289         private Rectangle fSubjectArea;
290         /** The tracker's subject control. */
291         private Control fSubjectControl;
292
293         /** Indicates whether the tracker is in restart mode ignoring hover events. */
294         private boolean fIsInRestartMode= false;
295         /** Indicates whether the tracker is computing the information to be presented. */
296         private boolean fIsComputing= false;
297         /** Indicates whether the mouse has been lost. */
298         private boolean fMouseLostWhileComputing= false;
299         /** Indicates whether the subject control's shell has been deactivated. */
300         private boolean fShellDeactivatedWhileComputing= false;
301
302         /**
303          * Creates a new mouse tracker.
304          */

305         public MouseTracker() {
306         }
307
308         /**
309          * Sets this mouse tracker's subject area, the area to be tracked in order
310          * to re-enable the information control manager.
311          *
312          * @param subjectArea the subject area
313          */

314         public void setSubjectArea(Rectangle subjectArea) {
315             Assert.isNotNull(subjectArea);
316             fSubjectArea= subjectArea;
317         }
318
319         /**
320          * Starts this mouse tracker. The given control becomes this tracker's subject control.
321          * Installs itself as mouse track listener on the subject control.
322          *
323          * @param subjectControl the subject control
324          */

325         public void start(Control subjectControl) {
326             fSubjectControl= subjectControl;
327             if (fSubjectControl != null && !fSubjectControl.isDisposed())
328                 fSubjectControl.addMouseTrackListener(this);
329
330             fIsInRestartMode= false;
331             fIsComputing= false;
332             fMouseLostWhileComputing= false;
333             fShellDeactivatedWhileComputing= false;
334         }
335
336         /**
337          * Stops this mouse tracker. Removes itself as mouse track, mouse move, and
338          * shell listener from the subject control.
339          */

340         public void stop() {
341             if (fSubjectControl != null && !fSubjectControl.isDisposed()) {
342                 fSubjectControl.removeMouseTrackListener(this);
343                 fSubjectControl.removeMouseMoveListener(this);
344                 fSubjectControl.getShell().removeShellListener(this);
345             }
346         }
347
348         /**
349          * Initiates the computation of the information to be presented. Sets the initial hover area
350          * to a small rectangle around the hover event location. Adds mouse move and shell activation listeners
351          * to track whether the computed information is, after completion, useful for presentation and to
352          * implement the restart function.
353          *
354          * @param event the mouse hover event
355          */

356         public void mouseHover(MouseEvent event) {
357
358             if (fIsComputing || fIsInRestartMode) return;
359
360             fIsInRestartMode= true;
361             fIsComputing= true;
362             fMouseLostWhileComputing= false;
363             fShellDeactivatedWhileComputing= false;
364
365             fHoverEventStateMask= event.stateMask;
366             fHoverEvent= event;
367             fHoverArea= new Rectangle(event.x - EPSILON, event.y - EPSILON, 2 * EPSILON, 2 * EPSILON );
368             if (fHoverArea.x < 0) fHoverArea.x= 0;
369             if (fHoverArea.y < 0) fHoverArea.y= 0;
370             setSubjectArea(fHoverArea);
371
372             if (fSubjectControl != null && !fSubjectControl.isDisposed()) {
373                 fSubjectControl.addMouseMoveListener(this);
374                 fSubjectControl.getShell().addShellListener(this);
375             }
376             doShowInformation();
377         }
378
379         /**
380          * Deactivates this tracker's restart function and enables the information control
381          * manager. Does not have any effect if the tracker is still executing the start function (i.e.
382          * computing the information to be presented.
383          */

384         protected void deactivate() {
385             if (fIsComputing) return;
386             fIsInRestartMode= false;
387             if (fSubjectControl != null && !fSubjectControl.isDisposed()) {
388                 fSubjectControl.removeMouseMoveListener(this);
389                 fSubjectControl.getShell().removeShellListener(this);
390             }
391         }
392
393         /*
394          * @see MouseTrackListener#mouseEnter(MouseEvent)
395          */

396         public void mouseEnter(MouseEvent e) {
397         }
398
399         /*
400          * @see MouseTrackListener#mouseExit(MouseEvent)
401          */

402         public void mouseExit(MouseEvent e) {
403             fMouseLostWhileComputing= true;
404             deactivate();
405         }
406
407         /*
408          * @see MouseMoveListener#mouseMove(MouseEvent)
409          */

410         public void mouseMove(MouseEvent event) {
411             if (!fSubjectArea.contains(event.x, event.y))
412                 deactivate();
413         }
414
415         /*
416          * @see ShellListener#shellDeactivated(ShellEvent)
417          */

418         public void shellDeactivated(ShellEvent e) {
419             fShellDeactivatedWhileComputing= true;
420             deactivate();
421         }
422
423         /*
424          * @see ShellListener#shellIconified(ShellEvent)
425          */

426         public void shellIconified(ShellEvent e) {
427             fShellDeactivatedWhileComputing= true;
428             deactivate();
429         }
430
431         /**
432          * Tells this tracker that the start function processing has been completed.
433          */

434         public void computationCompleted() {
435             fIsComputing= false;
436             fMouseLostWhileComputing= false;
437             fShellDeactivatedWhileComputing= false;
438         }
439
440         /**
441          * Determines whether the computed information is still useful for presentation.
442          * This is not the case, if the shell of the subject control has been deactivated, the mouse
443          * left the subject control, or the mouse moved on, so that it is no longer in the subject
444          * area.
445          *
446          * @return <code>true</code> if information is still useful for presentation, <code>false</code> otherwise
447          */

448         public boolean isMouseLost() {
449
450             if (fMouseLostWhileComputing || fShellDeactivatedWhileComputing)
451                 return true;
452
453             if (fSubjectControl != null && !fSubjectControl.isDisposed()) {
454                 Display display= fSubjectControl.getDisplay();
455                 Point p= display.getCursorLocation();
456                 p= fSubjectControl.toControl(p);
457                 if (!fSubjectArea.contains(p) && !fHoverArea.contains(p))
458                     return true;
459             }
460
461             return false;
462         }
463     }
464
465     /** The mouse tracker on the subject control */
466     private MouseTracker fMouseTracker= new MouseTracker();
467     /**
468      * The remembered hover event.
469      * @since 3.0
470      */

471     private MouseEvent fHoverEvent= null;
472     /** The remembered hover event sate mask of the keyboard modifiers */
473     private int fHoverEventStateMask= 0;
474
475     /**
476      * Creates a new hover information control manager using the given information control creator.
477      * By default a <code>Closer</code> instance is set as this manager's closer.
478      *
479      * @param creator the information control creator
480      */

481     protected AbstractHoverInformationControlManager(IInformationControlCreator creator) {
482         super(creator);
483         setCloser(new Closer());
484     }
485
486     /*
487      * @see org.eclipse.jface.text.AbstractInformationControlManager#presentInformation()
488      */

489     protected void presentInformation() {
490         if (fMouseTracker == null) {
491             super.presentInformation();
492             return;
493         }
494
495         Rectangle area= getSubjectArea();
496         if (area != null)
497             fMouseTracker.setSubjectArea(area);
498
499         if (fMouseTracker.isMouseLost()) {
500             fMouseTracker.computationCompleted();
501             fMouseTracker.deactivate();
502         } else {
503             fMouseTracker.computationCompleted();
504             super.presentInformation();
505         }
506     }
507
508     /**
509      * {@inheritDoc}
510      * @deprecated visibility will be changed to protected
511      */

512     public void setEnabled(boolean enabled) {
513
514         boolean was= isEnabled();
515         super.setEnabled(enabled);
516         boolean is= isEnabled();
517
518         if (was != is && fMouseTracker != null) {
519             if (is)
520                 fMouseTracker.start(getSubjectControl());
521             else
522                 fMouseTracker.stop();
523         }
524     }
525
526     /**
527      * Disposes this manager's information control.
528      */

529     public void dispose() {
530         if (fMouseTracker != null) {
531             fMouseTracker.stop();
532             fMouseTracker.fSubjectControl= null;
533             fMouseTracker= null;
534         }
535         super.dispose();
536     }
537
538     /**
539      * Returns the location at which the most recent mouse hover event
540      * has been issued.
541      *
542      * @return the location of the most recent mouse hover event
543      */

544     protected Point getHoverEventLocation() {
545         return fHoverEvent != null ? new Point(fHoverEvent.x, fHoverEvent.y) : new Point(-1, -1);
546     }
547
548     /**
549      * Returns the most recent mouse hover event.
550      *
551      * @return the most recent mouse hover event or <code>null</code>
552      * @since 3.0
553      */

554     protected MouseEvent getHoverEvent() {
555         return fHoverEvent;
556     }
557
558     /**
559      * Returns the SWT event state of the most recent mouse hover event.
560      *
561      * @return the SWT event state of the most recent mouse hover event
562      */

563     protected int getHoverEventStateMask() {
564         return fHoverEventStateMask;
565     }
566
567 }
568
Popular Tags