1 19 20 package org.netbeans.editor; 21 22 import javax.swing.JComponent ; 23 import java.awt.Dimension ; 24 import java.awt.Rectangle ; 25 import java.awt.Graphics ; 26 import java.awt.Color ; 27 import java.awt.Font ; 28 import java.awt.Image ; 29 import java.net.URL ; 30 import java.net.MalformedURLException ; 31 import java.awt.Toolkit ; 32 import java.awt.event.MouseAdapter ; 33 import java.awt.event.MouseEvent ; 34 import javax.swing.event.DocumentListener ; 35 import javax.swing.event.DocumentEvent ; 36 import javax.swing.text.BadLocationException ; 37 import java.awt.FontMetrics ; 38 import java.awt.Insets ; 39 import java.awt.Point ; 40 import java.awt.Shape ; 41 import java.awt.image.ImageObserver ; 42 import java.awt.event.InputEvent ; 43 import javax.swing.JPopupMenu ; 44 import org.netbeans.editor.Utilities; 45 import javax.swing.event.PopupMenuListener ; 46 import javax.swing.event.PopupMenuEvent ; 47 import org.netbeans.editor.FontMetricsCache; 48 import java.beans.PropertyChangeListener ; 49 import java.beans.PropertyChangeEvent ; 50 import java.awt.event.*; 51 import java.lang.ref.WeakReference ; 52 import java.util.Map ; 53 import javax.swing.Action ; 54 import javax.accessibility.*; 55 import javax.swing.SwingUtilities ; 56 import javax.swing.text.AbstractDocument ; 57 import javax.swing.text.BoxView ; 58 import javax.swing.text.Element ; 59 import javax.swing.text.JTextComponent ; 60 import javax.swing.text.Position ; 61 import javax.swing.text.View ; 62 import org.netbeans.api.editor.fold.FoldHierarchy; 63 import org.netbeans.api.editor.fold.FoldHierarchyEvent; 64 import org.netbeans.api.editor.fold.FoldHierarchyListener; 65 import org.openide.ErrorManager; 66 import org.openide.util.NbBundle; 67 68 77 78 public class GlyphGutter extends JComponent implements Annotations.AnnotationsListener, Accessible, SettingsChangeListener, SideBarFactory { 79 80 81 private EditorUI editorUI; 82 83 84 private BaseDocument doc; 85 86 87 private Annotations annos; 88 89 90 private Image gutterButton; 91 92 93 private Color backgroundColor; 94 95 96 private Color foreColor; 97 98 99 private Font font; 100 101 102 private int lineHeight; 103 104 106 private boolean init; 107 108 109 private int glyphGutterWidth; 110 111 112 private final static int glyphWidth = 16; 113 114 115 private final static int glyphButtonWidth = 9; 116 117 120 private final static int leftGap= 10; 121 122 125 private final static int rightGap= 4; 126 127 128 private boolean showLineNumbers = true; 129 130 131 private ImageObserver imgObserver = null; 132 133 134 private static final int ENLARGE_GUTTER_HEIGHT = 300; 135 136 137 private int highestLineNumber = 0; 138 139 140 private boolean drawOverLineNumbers = false; 141 142 144 private int cachedCountOfAnnos = -1; 145 private int cachedCountOfAnnosForLine = -1; 146 147 148 private PropertyChangeListener annoTypesListener; 149 private PropertyChangeListener editorUIListener; 150 private GlyphGutter.GlyphGutterFoldHierarchyListener glyphGutterFoldHierarchyListener; 151 private GutterMouseListener gutterMouseListener; 152 private FoldHierarchy foldHierarchy; 153 private Map renderingHints; 154 155 public GlyphGutter(){} 156 157 public GlyphGutter(EditorUI editorUI) { 158 super(); 159 this.editorUI = editorUI; 160 init = false; 161 doc = editorUI.getDocument(); 162 annos = doc.getAnnotations(); 163 164 annos.addAnnotationsListener(this); 167 168 init(); 170 update(); 171 Settings.addSettingsChangeListener(this); 172 setMaximumSize(new Dimension (Integer.MAX_VALUE, Integer.MAX_VALUE)); 173 foldHierarchy = FoldHierarchy.get(editorUI.getComponent()); 174 glyphGutterFoldHierarchyListener = new GlyphGutterFoldHierarchyListener(); 175 foldHierarchy.addFoldHierarchyListener(glyphGutterFoldHierarchyListener); 176 editorUIListener = new EditorUIListener(); 177 editorUI.addPropertyChangeListener(editorUIListener); 178 updateRenderingHints(); 179 setOpaque (true); 180 } 181 182 private void updateRenderingHints(){ 183 JTextComponent comp = editorUI.getComponent(); 184 if (comp == null) return; 185 Object value = (Map )(Toolkit.getDefaultToolkit().getDesktopProperty( 186 "awt.font.desktophints")); if (value == null) { 191 value = Settings.getValue(Utilities.getKitClass(comp), 192 SettingsNames.RENDERING_HINTS); 193 } 194 renderingHints = (value instanceof Map ) ? (java.util.Map )value : null; 195 } 196 197 public void settingsChange(SettingsChangeEvent evt) { 198 if (editorUI == null) return; 200 201 JTextComponent component = editorUI.getComponent(); 202 if (evt == null || component == null) return; 203 204 String settingName = evt.getSettingName(); 205 if (settingName == null || SettingsNames.RENDERING_HINTS.equals(settingName)) { 206 updateRenderingHints(); 207 } 208 209 Class kitClass = evt.getKitClass(); 210 if (Utilities.getKitClass(component) != kitClass){ 211 Rectangle rect = component.getVisibleRect(); 212 if (rect!=null && rect.width == 0){ 213 if (SwingUtilities.isEventDispatchThread()) { 214 resize(); 215 } else { 216 SwingUtilities.invokeLater( 217 new Runnable () { 218 public void run() { 219 resize(); 220 } 221 } 222 ); 223 } 224 } 225 } 226 } 227 228 229 232 public AccessibleContext getAccessibleContext () { 233 if (accessibleContext == null) { 234 accessibleContext = new AccessibleJComponent() { 235 public AccessibleRole getAccessibleRole() { 236 return AccessibleRole.PANEL; 237 } 238 }; 239 } 240 return accessibleContext; 241 } 242 243 244 protected void init() { 245 if (editorUI == null) 246 return ; 247 248 URL imageURL = null; 249 250 try { 251 imageURL = new URL ("nbresloc:/org/netbeans/editor/resources/glyphbutton.gif"); } catch (MalformedURLException ex) { 254 Utilities.annotateLoggable(ex); 255 return; 256 } 257 258 if (imageURL != null) 259 gutterButton = Toolkit.getDefaultToolkit().getImage(imageURL); 260 261 setToolTipText (""); 262 getAccessibleContext().setAccessibleName(NbBundle.getBundle(BaseKit.class).getString("ACSN_Glyph_Gutter")); getAccessibleContext().setAccessibleDescription(NbBundle.getBundle(BaseKit.class).getString("ACSD_Glyph_Gutter")); 265 gutterMouseListener = new GutterMouseListener (); 269 addMouseListener (gutterMouseListener); 270 addMouseMotionListener (gutterMouseListener); 271 272 imgObserver = new Observer (this); 274 275 AnnotationTypes.getTypes().addPropertyChangeListener( annoTypesListener = new PropertyChangeListener () { 276 public void propertyChange (PropertyChangeEvent evt) { 277 if (evt.getPropertyName() == AnnotationTypes.PROP_GLYPHS_OVER_LINE_NUMBERS || 278 evt.getPropertyName() == AnnotationTypes.PROP_SHOW_GLYPH_GUTTER) { 279 update(); 280 } 281 } 282 }); 283 284 } 285 286 288 public void update() { 289 if (editorUI == null) 290 return ; 291 Coloring lineColoring = (Coloring)editorUI.getColoringMap().get(SettingsNames.LINE_NUMBER_COLORING); 292 Coloring defaultColoring = (Coloring)editorUI.getDefaultColoring(); 293 294 if (lineColoring == null) 299 return; 300 301 if (lineColoring.getBackColor() != null) 302 backgroundColor = lineColoring.getBackColor(); 303 else 304 backgroundColor = defaultColoring.getBackColor(); 305 306 if (lineColoring.getForeColor() != null) 307 foreColor = lineColoring.getForeColor(); 308 else 309 foreColor = defaultColoring.getForeColor(); 310 311 if (lineColoring.getFont() != null) { 312 Font lineFont = lineColoring.getFont(); 313 font = (lineFont != null) ? lineFont.deriveFont((float)lineFont.getSize()-1) : null; 314 } else { 315 font = defaultColoring.getFont(); 316 font = new Font ("Monospaced", Font.PLAIN, font.getSize()-1); } 318 319 lineHeight = editorUI.getLineHeight(); 320 321 showLineNumbers = editorUI.lineNumberVisibleSetting; 322 323 drawOverLineNumbers = AnnotationTypes.getTypes().isGlyphsOverLineNumbers().booleanValue(); 324 325 326 327 init = true; 328 329 highestLineNumber = getLineCount(); 331 332 repaint(); 333 resize(); 334 } 335 336 337 protected void resize() { 338 Dimension dim = new Dimension (); 339 glyphGutterWidth = getWidthDimension(); 340 dim.width = glyphGutterWidth; 341 dim.height = getHeightDimension(); 342 343 344 dim.height += ENLARGE_GUTTER_HEIGHT * lineHeight; 347 348 setPreferredSize(dim); 349 350 revalidate(); 351 } 352 353 354 protected int getLineCount() { 355 int lineCnt; 356 try { 357 if (doc != null) { 358 lineCnt = Utilities.getLineOffset(doc, doc.getLength()) + 1; 359 } else { lineCnt = 1; 361 } 362 } catch (BadLocationException e) { 363 lineCnt = 1; 364 } 365 return lineCnt; 366 } 367 368 369 protected int getDigitCount(int number) { 370 return Integer.toString(number).length(); 371 } 372 373 protected int getLineNumberWidth() { 374 int newWidth = 0; 375 376 if (editorUI != null) { 377 383 newWidth += getDigitCount(highestLineNumber) * editorUI.getLineNumberDigitWidth(); 384 } 385 386 return newWidth; 387 } 388 389 protected int getWidthDimension() { 390 int newWidth = 0; 391 392 if (showLineNumbers) { 393 int lineNumberWidth = getLineNumberWidth(); 394 newWidth = leftGap + lineNumberWidth + rightGap; 395 } else { 396 if (editorUI != null) { 397 if (annos.isGlyphColumn() || 398 AnnotationTypes.getTypes().isShowGlyphGutter().booleanValue()){ 399 newWidth += glyphWidth; 400 } 401 402 if (annos.isGlyphButtonColumn()){ 403 newWidth += glyphButtonWidth; 404 } 405 } 406 } 407 408 return newWidth; 409 } 410 411 protected int getHeightDimension() { 412 if (editorUI == null) 413 return 0; 414 JComponent comp = editorUI.getComponent(); 415 if (comp == null) 416 return 0; 417 return highestLineNumber * lineHeight + (int)comp.getSize().getHeight(); 418 } 419 420 421 void paintGutterForView(Graphics g, View view, int y){ 422 if (editorUI == null) 423 return ; 424 Rectangle clip = g.getClipBounds(); 425 JTextComponent component = editorUI.getComponent(); 426 if (component == null) return; 427 BaseTextUI textUI = (BaseTextUI)component.getUI(); 428 429 430 Rectangle rec = new Rectangle (0, y, 0, editorUI.getLineHeight()); 431 432 437 g.setFont(font); 438 g.setColor(foreColor); 439 440 FontMetrics fm = FontMetricsCache.getFontMetrics(font, this); 441 Element rootElem = textUI.getRootView(component).getElement(); 442 int line = rootElem.getElementIndex(view.getStartOffset()); 443 int lineWithAnno = annos.getNextLineWithAnnotation(line); 445 446 int lineNumberWidth = fm.stringWidth(String.valueOf(line + 1)); 447 448 int count = annos.getNumberOfAnnotations(line); 449 AnnotationDesc anno = annos.getActiveAnnotation(line); 450 451 if (showLineNumbers){ 452 boolean glyphHasIcon = false; 453 if (line == lineWithAnno){ 454 if (anno != null && !(anno.isDefaultGlyph()&&count == 1) && anno.getGlyph()!=null){ 455 glyphHasIcon = true; 456 } 457 } 458 if ((!glyphHasIcon) || 459 (!drawOverLineNumbers) || 460 (drawOverLineNumbers && line != lineWithAnno) ) { 461 g.drawString(String.valueOf(line + 1), glyphGutterWidth-lineNumberWidth-rightGap, y + editorUI.getLineAscent()); 462 } 463 } 464 465 if (line == lineWithAnno) { 467 int xPos = (showLineNumbers) ? getLineNumberWidth() : 0; 468 if (drawOverLineNumbers) { 469 xPos = getWidth() - glyphWidth; 470 if (count > 1) 471 xPos -= glyphButtonWidth; 472 } 473 474 if (anno != null) { 475 if ( ! (count == 1 && anno.isDefaultGlyph()) ) { 478 if (anno.getGlyph() != null && prepareImage(anno.getGlyph(), imgObserver)) 479 g.drawImage(anno.getGlyph(), xPos, y + (lineHeight-anno.getGlyph().getHeight(null)) / 2 + 1, null); 480 } 481 } 482 483 if (count > 1) 485 if (anno.getGlyph() != null && prepareImage(gutterButton, imgObserver) && prepareImage(anno.getGlyph(), imgObserver)) 486 g.drawImage(gutterButton, xPos+glyphWidth-1, y + (lineHeight-anno.getGlyph().getHeight(null)) / 2, null); 487 488 lineWithAnno = annos.getNextLineWithAnnotation(line+1); 490 } 491 } 492 493 494 public void paintComponent(Graphics g) { 495 super.paintComponent(g); 496 if (editorUI == null) 497 return ; 498 499 if (renderingHints != null) { 501 ((java.awt.Graphics2D )g).setRenderingHints(renderingHints); 502 } 503 504 if (!init) return; 506 507 Rectangle clip = g.getClipBounds(); 508 509 JTextComponent component = editorUI.getComponent(); 510 if (component == null) return; 511 512 BaseTextUI textUI = (BaseTextUI)component.getUI(); 513 Element rootElem = textUI.getRootView(component).getElement(); 514 515 View rootView = Utilities.getDocumentView(component); 516 if (rootView == null) return; 517 518 g.setColor(backgroundColor); 519 g.fillRect(clip.x, clip.y, clip.width, clip.height); 520 521 g.setColor(SettingsDefaults.defaultGutterLine); 523 g.drawLine(glyphGutterWidth-1, clip.y, glyphGutterWidth-1, clip.height + clip.y); 524 525 AbstractDocument doc = (AbstractDocument )component.getDocument(); 526 doc.readLock(); 527 try{ 528 foldHierarchy.lock(); 529 try{ 530 int startPos = textUI.getPosFromY(clip.y); 531 int startViewIndex = rootView.getViewIndex(startPos,Position.Bias.Forward); 532 int rootViewCount = rootView.getViewCount(); 533 534 if (startViewIndex >= 0 && startViewIndex < rootViewCount) { 535 int lineWithAnno = annos.getNextLineWithAnnotation(rootElem.getElementIndex(startPos)); 537 Rectangle rec = textUI.modelToView(component, rootView.getView(startViewIndex).getStartOffset()); 538 int y = (rec == null) ? 0 : rec.y; 539 540 int clipEndY = clip.y + clip.height; 541 for (int i = startViewIndex; i < rootViewCount; i++){ 542 View view = rootView.getView(i); 543 paintGutterForView(g, view, y); 544 y += editorUI.getLineHeight(); 545 if (y >= clipEndY) { 546 break; 547 } 548 } 549 } 550 551 }finally{ 552 foldHierarchy.unlock(); 553 } 554 }catch(BadLocationException ble){ 555 ErrorManager.getDefault().notify(ble); 556 }finally{ 557 doc.readUnlock(); 558 } 559 } 560 561 562 public void changedLine(int line) { 563 564 if (!init || editorUI == null) 565 return; 566 567 cachedCountOfAnnos = -1; 569 570 if (line > 0) 572 line--; 573 JTextComponent component = editorUI.getComponent(); 574 if (component!=null){ 575 BaseTextUI textUI = (BaseTextUI)component.getUI(); 576 try{ 577 Element rootElem = component.getDocument().getDefaultRootElement(); 578 if (line >= rootElem.getElementCount()) { return; 580 } 581 Element lineElem = rootElem.getElement(line); 582 if (lineElem == null) return; 583 int lineOffset = lineElem.getStartOffset(); 584 Rectangle mtvRect = textUI.modelToView(component, lineOffset); 585 if (mtvRect == null) return; 586 repaint(0, mtvRect.y, (int)getSize().getWidth(), 3*lineHeight); 587 checkSize(); 588 }catch(BadLocationException ble){ 589 ErrorManager.getDefault().notify(ble); 590 } 591 } 592 } 593 594 595 public void changedAll() { 596 597 if (!init || editorUI == null) 598 return; 599 600 cachedCountOfAnnos = -1; 602 603 int lineCnt; 604 try { 605 lineCnt = Utilities.getLineOffset(doc, doc.getLength()) + 1; 606 } catch (BadLocationException e) { 607 lineCnt = 1; 608 } 609 610 repaint(); 611 checkSize(); 612 } 613 614 615 protected void checkSize() { 616 int count = getLineCount(); 617 if (count > highestLineNumber) { 618 highestLineNumber = count; 619 } 620 Dimension dim = getPreferredSize(); 621 if (getWidthDimension() > dim.width || 622 getHeightDimension() > dim.height) { 623 resize(); 624 } 625 626 } 627 628 629 public String getToolTipText (MouseEvent e) { 631 if (editorUI == null) 632 return null; 633 int line = getLineFromMouseEvent(e); 634 if (annos.getNumberOfAnnotations(line) == 0) 635 return null; 636 if (isMouseOverCycleButton(e) && annos.getNumberOfAnnotations(line) > 1) { 637 return java.text.MessageFormat.format ( 638 NbBundle.getBundle(BaseKit.class).getString ("cycling-glyph_tooltip"), new Object [] { new Integer (annos.getNumberOfAnnotations(line)) }); 640 } 641 else if (isMouseOverGlyph(e)) { 642 return annos.getActiveAnnotation(line).getShortDescription(); 643 } 644 else 645 return null; 646 } 647 648 649 private int getXPosOfGlyph(int line) { 650 if (editorUI == null) 651 return 0; 652 int xPos = (showLineNumbers) ? getLineNumberWidth() : 0; 653 if (drawOverLineNumbers) { 654 xPos = getWidth() - glyphWidth; 655 if (cachedCountOfAnnos == -1 || cachedCountOfAnnosForLine != line) { 656 cachedCountOfAnnos = annos.getNumberOfAnnotations(line); 657 cachedCountOfAnnosForLine = line; 658 } 659 if (cachedCountOfAnnos > 1) 660 xPos -= glyphButtonWidth; 661 } 662 return xPos; 663 } 664 665 666 private boolean isMouseOverGlyph(MouseEvent e) { 667 int line = getLineFromMouseEvent(e); 668 if (e.getX() >= getXPosOfGlyph(line) && e.getX() <= getXPosOfGlyph(line)+glyphWidth) 669 return true; 670 else 671 return false; 672 } 673 674 675 private boolean isMouseOverCycleButton(MouseEvent e) { 676 int line = getLineFromMouseEvent(e); 677 if (e.getX() >= getXPosOfGlyph(line)+glyphWidth && e.getX() <= getXPosOfGlyph(line)+glyphWidth+glyphButtonWidth) 678 return true; 679 else 680 return false; 681 } 682 683 public JComponent createSideBar(JTextComponent target) { 684 EditorUI eui = Utilities.getEditorUI(target); 685 if (eui == null){ 686 return null; 687 } 688 GlyphGutter glyph = new GlyphGutter(eui); 689 eui.setGlyphGutter(glyph); 690 return glyph; 691 } 692 693 private int getLineFromMouseEvent(MouseEvent e){ 694 int line = -1; 695 if (editorUI != null) { 696 try{ 697 JTextComponent component = editorUI.getComponent(); 698 BaseTextUI textUI = (BaseTextUI)component.getUI(); 699 int clickOffset = textUI.viewToModel(component, new Point (0, e.getY())); 700 line = Utilities.getLineOffset(doc, clickOffset); 701 }catch (BadLocationException ble){ 702 ble.printStackTrace(); 703 } 704 } 705 return line; 706 } 707 708 class GutterMouseListener extends MouseAdapter implements MouseMotionListener { 709 710 711 private int dragStartLine; 712 713 private int dragEndLine; 714 715 private int currentEndLine; 716 717 private boolean selectForward; 718 719 public void mouseClicked(MouseEvent e) { 720 if (editorUI==null) 721 return; 722 if (e.getModifiers() == InputEvent.BUTTON1_MASK) { 724 if (isMouseOverCycleButton(e)) { 725 int line = getLineFromMouseEvent(e); 726 annos.activateNextAnnotation(line); 727 } else { 728 Action actions[] = ImplementationProvider.getDefault().getGlyphGutterActions(editorUI.getComponent()); 729 if (actions != null && actions.length >0) { 730 Action a = actions[0]; if (a!=null && a.isEnabled()){ 732 int currentLine = -1; 733 int line = getLineFromMouseEvent(e); 734 if (line == -1) return; 735 try { 736 currentLine = Utilities.getLineOffset(doc, editorUI.getComponent().getCaret().getDot()); 737 } catch (BadLocationException ex) { 738 return; 739 } 740 if (line != currentLine) { 741 int offset = Utilities.getRowStartFromLineOffset(doc, line); 742 JumpList.checkAddEntry(); 743 editorUI.getComponent().getCaret().setDot(offset); 744 } 745 a.actionPerformed(new ActionEvent(editorUI.getComponent(), 0, "")); 746 repaint(); 747 } 748 } else { 749 Toolkit.getDefaultToolkit().beep(); 750 } 751 } 752 } 753 } 754 755 private void showPopup(MouseEvent e) { 756 if (editorUI == null) 757 return; 758 if (e.isPopupTrigger()) { 760 int line = getLineFromMouseEvent(e); 761 int offset; 762 if (annos.getActiveAnnotation(line) != null) 763 offset = annos.getActiveAnnotation(line).getOffset(); 764 else 765 offset = Utilities.getRowStartFromLineOffset(doc, line); 766 if (editorUI.getComponent().getCaret().getDot() != offset) 767 JumpList.checkAddEntry(); 768 editorUI.getComponent().getCaret().setDot(offset); 769 JPopupMenu pm = annos.createPopupMenu(Utilities.getKit(editorUI.getComponent()), line); 770 if (pm != null) { 771 pm.show(GlyphGutter.this, e.getX(), e.getY()); 772 } 773 pm.addPopupMenuListener( new PopupMenuListener () { 774 public void popupMenuCanceled(PopupMenuEvent e2) { 775 editorUI.getComponent().requestFocus(); 776 } 777 public void popupMenuWillBecomeInvisible(PopupMenuEvent e2) { 778 editorUI.getComponent().requestFocus(); 779 } 780 public void popupMenuWillBecomeVisible(PopupMenuEvent e2) { 781 } 782 }); 783 } 784 } 785 786 public void mouseReleased(MouseEvent e) { 787 showPopup(e); 788 } 789 790 public void mousePressed (MouseEvent e) { 791 showPopup(e); 792 } 801 802 public void mouseDragged(MouseEvent e) { 803 } 807 808 public void mouseMoved(MouseEvent e) {} 809 810 811 private void updateSelection (boolean newSelection) { 812 if (editorUI == null) 813 return ; 814 javax.swing.text.JTextComponent comp = Utilities.getLastActiveComponent (); 815 try { 816 if (newSelection) { 817 selectForward = true; 818 int rowStart = Utilities.getRowStartFromLineOffset (doc, dragStartLine); 821 if (rowStart < 0) { 822 rowStart = Utilities.getRowStart (doc, doc.getLength ()); 823 dragStartLine = Utilities.getLineOffset (doc, rowStart); 824 } 825 comp.setCaretPosition (rowStart); 826 int offSet = Utilities.getRowEnd (doc, rowStart); 827 if (offSet < doc.getLength()) { 828 offSet = offSet + 1; 829 } 830 comp.moveCaretPosition (offSet); 831 currentEndLine = dragEndLine = dragStartLine; 832 } else { 833 if (currentEndLine == dragEndLine) return; 834 if (dragEndLine < dragStartLine) { 836 if (selectForward) { 837 int offSet = Utilities.getRowStartFromLineOffset (doc, dragStartLine + 1); 839 if (offSet < 0) { 840 offSet = Utilities.getRowEnd (doc, Utilities.getRowStartFromLineOffset (doc, dragStartLine)); 841 } 842 comp.setCaretPosition (offSet); 843 selectForward = false; 844 } 845 int rowStart = Utilities.getRowStartFromLineOffset (doc, dragEndLine); 846 if (rowStart < 0) rowStart = 0; 847 comp.moveCaretPosition (rowStart); 848 } 849 else { 851 if (! selectForward) { 852 comp.setCaretPosition (Utilities.getRowStartFromLineOffset (doc, dragStartLine)); 854 selectForward = true; 855 } 856 int offSet = Utilities.getRowStartFromLineOffset (doc, dragEndLine + 1);; 858 if (offSet < 0) { 860 offSet = doc.getLength (); 861 } 862 comp.moveCaretPosition (offSet); 863 } 864 } 865 currentEndLine = dragEndLine; 866 } catch (BadLocationException ble) { 867 ErrorManager.getDefault().notify(ble); 868 } 869 } 870 } 871 872 class GlyphGutterFoldHierarchyListener implements FoldHierarchyListener{ 873 874 public GlyphGutterFoldHierarchyListener(){ 875 } 876 877 public void foldHierarchyChanged(FoldHierarchyEvent evt) { 878 repaint(); 879 } 880 } 881 882 883 class EditorUIListener implements PropertyChangeListener { 884 public void propertyChange (PropertyChangeEvent evt) { 885 if (evt!=null && EditorUI.COMPONENT_PROPERTY.equals(evt.getPropertyName())) { 886 if (evt.getNewValue() == null){ 887 editorUI.removePropertyChangeListener(editorUIListener); 889 annos.removeAnnotationsListener(GlyphGutter.this); 890 foldHierarchy.removeFoldHierarchyListener(glyphGutterFoldHierarchyListener); 891 if (gutterMouseListener!=null){ 892 removeMouseListener(gutterMouseListener); 893 removeMouseMotionListener(gutterMouseListener); 894 } 895 if (annoTypesListener !=null){ 896 AnnotationTypes.getTypes().removePropertyChangeListener(annoTypesListener); 897 } 898 foldHierarchy.removeFoldHierarchyListener(glyphGutterFoldHierarchyListener); 899 foldHierarchy = null; 900 doc = null; 902 editorUI.removePropertyChangeListener(this); 903 editorUI = null; 904 annos = null; 905 } 906 } 907 } 908 } 909 910 private static class Observer implements ImageObserver { 911 912 WeakReference glyphGutter; 913 914 private Observer(GlyphGutter gutter) { 915 glyphGutter = new WeakReference (gutter); 916 } 917 918 public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) { 919 if ((infoflags & ImageObserver.ALLBITS) == ImageObserver.ALLBITS) { 920 GlyphGutter obj = (GlyphGutter)glyphGutter.get(); 921 if (obj != null) 922 obj.repaint(); 923 } 924 return true; 925 } 926 } 927 928 } 929 | Popular Tags |