1 11 package org.eclipse.jface.text.hyperlink; 12 13 import java.util.ArrayList ; 14 import java.util.Arrays ; 15 import java.util.Iterator ; 16 import java.util.List ; 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 47 public class HyperlinkManager implements ITextListener, Listener, KeyListener, MouseListener, MouseMoveListener, FocusListener { 48 49 52 public static final class DETECTION_STRATEGY { 53 54 String fName; 55 56 private DETECTION_STRATEGY(String name) { 57 fName= name; 58 } 59 60 63 public String toString() { 64 return fName; 65 } 66 } 67 68 69 74 public static final DETECTION_STRATEGY FIRST= new DETECTION_STRATEGY("first"); 76 84 public static final DETECTION_STRATEGY ALL= new DETECTION_STRATEGY("all"); 86 95 public static final DETECTION_STRATEGY LONGEST_REGION_ALL= new DETECTION_STRATEGY("all with same longest region"); 97 102 public static final DETECTION_STRATEGY LONGEST_REGION_FIRST= new DETECTION_STRATEGY("first with longest region"); 104 105 106 private ITextViewer fTextViewer; 107 108 private boolean fActive; 109 110 private int fHyperlinkStateMask; 111 115 private int fActiveHyperlinkStateMask; 116 117 private IHyperlink[] fActiveHyperlinks; 118 119 private IHyperlinkDetector[] fHyperlinkDetectors; 120 121 private IHyperlinkPresenter fHyperlinkPresenter; 122 123 private final DETECTION_STRATEGY fDetectionStrategy; 124 125 126 131 public HyperlinkManager(DETECTION_STRATEGY detectionStrategy) { 132 Assert.isNotNull(detectionStrategy); 133 fDetectionStrategy= detectionStrategy; 134 } 135 136 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 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 198 public void setHyperlinkStateMask(int eventStateMask) { 199 fHyperlinkStateMask= eventStateMask; 200 } 201 202 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 228 protected void deactivate() { 229 fHyperlinkPresenter.hideHyperlinks(); 230 fActive= false; 231 } 232 233 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 allHyperlinks= new ArrayList (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 iter= new ArrayList (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 303 protected int computeLongestHyperlinkLength(List hyperlinks) { 304 Assert.isLegal(hyperlinks != null && !hyperlinks.isEmpty()); 305 Iterator 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 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 e) { 345 return -1; 346 } 347 } 348 349 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 } 380 381 384 public void keyReleased(KeyEvent event) { 385 } 386 387 390 public void mouseDoubleClick(MouseEvent e) { 391 392 } 393 394 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 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 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 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 493 public void focusGained(FocusEvent e) {} 494 495 498 public void focusLost(FocusEvent event) { 499 deactivate(); 500 } 501 502 506 public void handleEvent(Event event) { 507 deactivate(); 508 } 509 510 514 public void textChanged(TextEvent event) { 515 if (event.getDocumentEvent() != null) 516 deactivate(); 517 } 518 519 } 520 | Popular Tags |