KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jface > text > hyperlink > HyperlinkManager


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 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 package org.eclipse.jface.text.hyperlink;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.Arrays JavaDoc;
15 import java.util.Iterator JavaDoc;
16 import java.util.List JavaDoc;
17
18 import org.eclipse.swt.SWT;
19 import org.eclipse.swt.custom.StyledText;
20 import org.eclipse.swt.events.FocusEvent;
21 import org.eclipse.swt.events.FocusListener;
22 import org.eclipse.swt.events.KeyEvent;
23 import org.eclipse.swt.events.KeyListener;
24 import org.eclipse.swt.events.MouseEvent;
25 import org.eclipse.swt.events.MouseListener;
26 import org.eclipse.swt.events.MouseMoveListener;
27 import org.eclipse.swt.graphics.Point;
28 import org.eclipse.swt.widgets.Display;
29 import org.eclipse.swt.widgets.Event;
30 import org.eclipse.swt.widgets.Listener;
31
32 import org.eclipse.core.runtime.Assert;
33
34 import org.eclipse.jface.text.IRegion;
35 import org.eclipse.jface.text.ITextListener;
36 import org.eclipse.jface.text.ITextViewer;
37 import org.eclipse.jface.text.ITextViewerExtension5;
38 import org.eclipse.jface.text.Region;
39 import org.eclipse.jface.text.TextEvent;
40
41
42 /**
43  * Default implementation of a hyperlink manager.
44  *
45  * @since 3.1
46  */

47 public class HyperlinkManager implements ITextListener, Listener, KeyListener, MouseListener, MouseMoveListener, FocusListener {
48
49     /**
50      * Detection strategy.
51      */

52     public static final class DETECTION_STRATEGY {
53
54         String JavaDoc fName;
55
56         private DETECTION_STRATEGY(String JavaDoc name) {
57             fName= name;
58         }
59
60         /*
61          * @see java.lang.Object#toString()
62          */

63         public String JavaDoc toString() {
64             return fName;
65         }
66     }
67
68
69     /**
70      * The first detected hyperlink is passed to the
71      * hyperlink presenter and no further detector
72      * is consulted.
73      */

74     public static final DETECTION_STRATEGY FIRST= new DETECTION_STRATEGY("first"); //$NON-NLS-1$
75

76     /**
77      * All detected hyperlinks from all detectors are collected
78      * and passed to the hyperlink presenter.
79      * <p>
80      * This strategy is only allowed if {@link IHyperlinkPresenter#canShowMultipleHyperlinks()}
81      * returns <code>true</code>.
82      * </p>
83      */

84     public static final DETECTION_STRATEGY ALL= new DETECTION_STRATEGY("all"); //$NON-NLS-1$
85

86     /**
87      * All detected hyperlinks from all detectors are collected
88      * and all those with the longest region are passed to the
89      * hyperlink presenter.
90      * <p>
91      * This strategy is only allowed if {@link IHyperlinkPresenter#canShowMultipleHyperlinks()}
92      * returns <code>true</code>.
93      * </p>
94      */

95     public static final DETECTION_STRATEGY LONGEST_REGION_ALL= new DETECTION_STRATEGY("all with same longest region"); //$NON-NLS-1$
96

97     /**
98      * All detected hyperlinks from all detectors are collected
99      * and form all those with the longest region only the first
100      * one is passed to the hyperlink presenter.
101      */

102     public static final DETECTION_STRATEGY LONGEST_REGION_FIRST= new DETECTION_STRATEGY("first with longest region"); //$NON-NLS-1$
103

104
105     /** The text viewer on which this hyperlink manager works. */
106     private ITextViewer fTextViewer;
107     /** The session is active. */
108     private boolean fActive;
109     /** The key modifier mask. */
110     private int fHyperlinkStateMask;
111     /**
112      * The active key modifier mask.
113      * @since 3.3
114      */

115     private int fActiveHyperlinkStateMask;
116     /** The active hyperlinks. */
117     private IHyperlink[] fActiveHyperlinks;
118     /** The hyperlink detectors. */
119     private IHyperlinkDetector[] fHyperlinkDetectors;
120     /** The hyperlink presenter. */
121     private IHyperlinkPresenter fHyperlinkPresenter;
122     /** The detection strategy. */
123     private final DETECTION_STRATEGY fDetectionStrategy;
124
125
126     /**
127      * Creates a new hyperlink manager.
128      *
129      * @param detectionStrategy the detection strategy one of {{@link #ALL}, {@link #FIRST}, {@link #LONGEST_REGION_ALL}, {@link #LONGEST_REGION_FIRST}}
130      */

131     public HyperlinkManager(DETECTION_STRATEGY detectionStrategy) {
132         Assert.isNotNull(detectionStrategy);
133         fDetectionStrategy= detectionStrategy;
134     }
135
136     /**
137      * Installs this hyperlink manager with the given arguments.
138      *
139      * @param textViewer the text viewer
140      * @param hyperlinkPresenter the hyperlink presenter
141      * @param hyperlinkDetectors the array of hyperlink detectors, must not be empty
142      * @param eventStateMask the SWT event state mask to activate hyperlink mode
143      */

144     public void install(ITextViewer textViewer, IHyperlinkPresenter hyperlinkPresenter, IHyperlinkDetector[] hyperlinkDetectors, int eventStateMask) {
145         Assert.isNotNull(textViewer);
146         Assert.isNotNull(hyperlinkPresenter);
147         fTextViewer= textViewer;
148         fHyperlinkPresenter= hyperlinkPresenter;
149         Assert.isLegal(fHyperlinkPresenter.canShowMultipleHyperlinks() || fDetectionStrategy == FIRST || fDetectionStrategy == LONGEST_REGION_FIRST);
150         setHyperlinkDetectors(hyperlinkDetectors);
151         setHyperlinkStateMask(eventStateMask);
152
153         StyledText text= fTextViewer.getTextWidget();
154         if (text == null || text.isDisposed())
155             return;
156
157         text.getDisplay().addFilter(SWT.KeyUp, this);
158         text.addKeyListener(this);
159         text.addMouseListener(this);
160         text.addMouseMoveListener(this);
161         text.addFocusListener(this);
162
163         fTextViewer.addTextListener(this);
164         
165         fHyperlinkPresenter.install(fTextViewer);
166     }
167
168     /**
169      * Sets the hyperlink detectors for this hyperlink manager.
170      * <p>
171      * It is allowed to call this method after this
172      * hyperlink manger has been installed.
173      * </p>
174      *
175      * @param hyperlinkDetectors and array of hyperlink detectors, must not be empty
176      */

177     public void setHyperlinkDetectors(IHyperlinkDetector[] hyperlinkDetectors) {
178         Assert.isTrue(hyperlinkDetectors != null && hyperlinkDetectors.length > 0);
179         if (fHyperlinkDetectors == null)
180             fHyperlinkDetectors= hyperlinkDetectors;
181         else {
182             synchronized (fHyperlinkDetectors) {
183                 fHyperlinkDetectors= hyperlinkDetectors;
184             }
185         }
186     }
187
188     /**
189      * Sets the SWT event state mask which in combination
190      * with the left mouse button triggers the hyperlink mode.
191      * <p>
192      * It is allowed to call this method after this
193      * hyperlink manger has been installed.
194      * </p>
195      *
196      * @param eventStateMask the SWT event state mask to activate hyperlink mode
197      */

198     public void setHyperlinkStateMask(int eventStateMask) {
199         fHyperlinkStateMask= eventStateMask;
200     }
201
202     /**
203      * Uninstalls this hyperlink manager.
204      */

205     public void uninstall() {
206         deactivate();
207
208         StyledText text= fTextViewer.getTextWidget();
209         if (text != null && !text.isDisposed()) {
210             text.removeKeyListener(this);
211             text.getDisplay().removeFilter(SWT.KeyUp, this);
212             text.removeMouseListener(this);
213             text.removeMouseMoveListener(this);
214             text.removeFocusListener(this);
215         }
216         fTextViewer.removeTextListener(this);
217         
218         fHyperlinkPresenter.uninstall();
219
220         fHyperlinkPresenter= null;
221         fTextViewer= null;
222         fHyperlinkDetectors= null;
223     }
224
225     /**
226      * Deactivates the currently shown hyperlinks.
227      */

228     protected void deactivate() {
229         fHyperlinkPresenter.hideHyperlinks();
230         fActive= false;
231     }
232
233     /**
234      * Finds hyperlinks at the current offset.
235      *
236      * @return the hyperlinks or <code>null</code> if none.
237      */

238     protected IHyperlink[] findHyperlinks() {
239         int offset= getCurrentTextOffset();
240         if (offset == -1)
241             return null;
242
243         boolean canShowMultipleHyperlinks= fHyperlinkPresenter.canShowMultipleHyperlinks();
244         IRegion region= new Region(offset, 0);
245         List JavaDoc allHyperlinks= new ArrayList JavaDoc(fHyperlinkDetectors.length * 2);
246         synchronized (fHyperlinkDetectors) {
247             for (int i= 0, length= fHyperlinkDetectors.length; i < length; i++) {
248                 IHyperlinkDetector detector= fHyperlinkDetectors[i];
249                 if (detector == null)
250                     continue;
251                 
252                 if (detector instanceof IHyperlinkDetectorExtension2) {
253                     int stateMask= ((IHyperlinkDetectorExtension2)detector).getStateMask();
254                     if (stateMask != -1 && stateMask != fActiveHyperlinkStateMask)
255                         continue;
256                     else if (stateMask == -1 && fActiveHyperlinkStateMask != fHyperlinkStateMask)
257                     continue;
258                 } else if (fActiveHyperlinkStateMask != fHyperlinkStateMask)
259                     continue;
260
261                 IHyperlink[] hyperlinks= detector.detectHyperlinks(fTextViewer, region, canShowMultipleHyperlinks);
262                 if (hyperlinks == null)
263                     continue;
264
265                 Assert.isLegal(hyperlinks.length > 0);
266
267                 if (fDetectionStrategy == FIRST) {
268                     if (hyperlinks.length == 1)
269                         return hyperlinks;
270                     return new IHyperlink[] {hyperlinks[0]};
271                 }
272                 allHyperlinks.addAll(Arrays.asList(hyperlinks));
273             }
274         }
275
276         if (allHyperlinks.isEmpty())
277             return null;
278
279         if (fDetectionStrategy != ALL) {
280             int maxLength= computeLongestHyperlinkLength(allHyperlinks);
281             Iterator JavaDoc iter= new ArrayList JavaDoc(allHyperlinks).iterator();
282             while (iter.hasNext()) {
283                 IHyperlink hyperlink= (IHyperlink)iter.next();
284                 if (hyperlink.getHyperlinkRegion().getLength() < maxLength)
285                     allHyperlinks.remove(hyperlink);
286             }
287         }
288
289         if (fDetectionStrategy == LONGEST_REGION_FIRST)
290             return new IHyperlink[] {(IHyperlink)allHyperlinks.get(0)};
291
292         return (IHyperlink[])allHyperlinks.toArray(new IHyperlink[allHyperlinks.size()]);
293
294     }
295
296     /**
297      * Computes the length of the longest detected
298      * hyperlink.
299      *
300      * @param hyperlinks
301      * @return the length of the longest detected
302      */

303     protected int computeLongestHyperlinkLength(List JavaDoc hyperlinks) {
304         Assert.isLegal(hyperlinks != null && !hyperlinks.isEmpty());
305         Iterator JavaDoc iter= hyperlinks.iterator();
306         int length= Integer.MIN_VALUE;
307         while (iter.hasNext()) {
308             IRegion region= ((IHyperlink)iter.next()).getHyperlinkRegion();
309             if (region.getLength() < length)
310                 continue;
311             length= region.getLength();
312         }
313         return length;
314     }
315
316     /**
317      * Returns the current text offset.
318      *
319      * @return the current text offset
320      */

321     protected int getCurrentTextOffset() {
322
323         try {
324             StyledText text= fTextViewer.getTextWidget();
325             if (text == null || text.isDisposed())
326                 return -1;
327
328             Display display= text.getDisplay();
329             Point absolutePosition= display.getCursorLocation();
330             Point relativePosition= text.toControl(absolutePosition);
331
332             int widgetOffset= text.getOffsetAtLocation(relativePosition);
333             Point p= text.getLocationAtOffset(widgetOffset);
334             if (p.x > relativePosition.x)
335                 widgetOffset--;
336             
337             if (fTextViewer instanceof ITextViewerExtension5) {
338                 ITextViewerExtension5 extension= (ITextViewerExtension5)fTextViewer;
339                 return extension.widgetOffset2ModelOffset(widgetOffset);
340             }
341
342             return widgetOffset + fTextViewer.getVisibleRegion().getOffset();
343
344         } catch (IllegalArgumentException JavaDoc e) {
345             return -1;
346         }
347     }
348
349     /*
350      * @see org.eclipse.swt.events.KeyListener#keyPressed(org.eclipse.swt.events.KeyEvent)
351      */

352     public void keyPressed(KeyEvent event) {
353
354         if (fActive) {
355             deactivate();
356             return;
357         }
358
359         if (!isRegisteredStateMask(event.keyCode)) {
360             deactivate();
361             return;
362         }
363
364         fActive= true;
365         fActiveHyperlinkStateMask= event.keyCode;
366
367 // removed for #25871 (hyperlinks could interact with typing)
368
//
369
// ITextViewer viewer= getSourceViewer();
370
// if (viewer == null)
371
// return;
372
//
373
// IRegion region= getCurrentTextRegion(viewer);
374
// if (region == null)
375
// return;
376
//
377
// highlightRegion(viewer, region);
378
// activateCursor(viewer);
379
}
380
381     /*
382      * @see org.eclipse.swt.events.KeyListener#keyReleased(org.eclipse.swt.events.KeyEvent)
383      */

384     public void keyReleased(KeyEvent event) {
385     }
386
387     /*
388      * @see org.eclipse.swt.events.MouseListener#mouseDoubleClick(org.eclipse.swt.events.MouseEvent)
389      */

390     public void mouseDoubleClick(MouseEvent e) {
391
392     }
393
394     /*
395      * @see org.eclipse.swt.events.MouseListener#mouseDown(org.eclipse.swt.events.MouseEvent)
396      */

397     public void mouseDown(MouseEvent event) {
398
399         if (!fActive)
400             return;
401
402         if (event.stateMask != fActiveHyperlinkStateMask) {
403             deactivate();
404             return;
405         }
406
407         if (event.button != 1) {
408             deactivate();
409             return;
410         }
411     }
412
413     /*
414      * @see org.eclipse.swt.events.MouseListener#mouseUp(org.eclipse.swt.events.MouseEvent)
415      */

416     public void mouseUp(MouseEvent e) {
417
418         if (!fActive) {
419             fActiveHyperlinks= null;
420             return;
421         }
422
423         if (e.button != 1)
424             fActiveHyperlinks= null;
425
426         deactivate();
427
428         if (fActiveHyperlinks != null)
429             fActiveHyperlinks[0].open();
430     }
431
432     /*
433      * @see org.eclipse.swt.events.MouseMoveListener#mouseMove(org.eclipse.swt.events.MouseEvent)
434      */

435     public void mouseMove(MouseEvent event) {
436
437         if (!isRegisteredStateMask(event.stateMask)) {
438             if (fActive)
439                 deactivate();
440             
441             return;
442         }
443         
444         fActive= true;
445         fActiveHyperlinkStateMask= event.stateMask;
446
447         StyledText text= fTextViewer.getTextWidget();
448         if (text == null || text.isDisposed()) {
449             deactivate();
450             return;
451         }
452
453         if ((event.stateMask & SWT.BUTTON1) != 0 && text.getSelectionCount() != 0) {
454             deactivate();
455             return;
456         }
457
458         fActiveHyperlinks= findHyperlinks();
459         if (fActiveHyperlinks == null || fActiveHyperlinks.length == 0) {
460             fHyperlinkPresenter.hideHyperlinks();
461             return;
462         }
463
464         fHyperlinkPresenter.showHyperlinks(fActiveHyperlinks);
465
466     }
467     
468     /**
469      * Checks whether the given state mask is registered.
470      *
471      * @param stateMask
472      * @return <code>true</code> if a detector is registered for the given state mask
473      * @since 3.3
474      */

475     private boolean isRegisteredStateMask(int stateMask) {
476         if (stateMask == fHyperlinkStateMask)
477             return true;
478         
479         synchronized (fHyperlinkDetectors) {
480             for (int i= 0; i < fHyperlinkDetectors.length; i++) {
481                 if (fHyperlinkDetectors[i] instanceof IHyperlinkDetectorExtension2) {
482                     if (stateMask == ((IHyperlinkDetectorExtension2)fHyperlinkDetectors[i]).getStateMask())
483                         return true;
484                 }
485             }
486         }
487         return false;
488     }
489     
490     /*
491      * @see org.eclipse.swt.events.FocusListener#focusGained(org.eclipse.swt.events.FocusEvent)
492      */

493     public void focusGained(FocusEvent e) {}
494
495     /*
496      * @see org.eclipse.swt.events.FocusListener#focusLost(org.eclipse.swt.events.FocusEvent)
497      */

498     public void focusLost(FocusEvent event) {
499         deactivate();
500     }
501
502     /*
503      * @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event)
504      * @since 3.2
505      */

506     public void handleEvent(Event event) {
507         deactivate();
508     }
509     
510     /*
511      * @see org.eclipse.jface.text.ITextListener#textChanged(TextEvent)
512      * @since 3.2
513      */

514     public void textChanged(TextEvent event) {
515         if (event.getDocumentEvent() != null)
516             deactivate();
517     }
518
519 }
520
Popular Tags