1 package edu.rice.cs.drjava.ui; 2 3 import javax.swing.text.*; 4 import java.util.Vector ; 5 import java.awt.*; 6 import javax.swing.plaf.*; 7 import javax.swing.*; 8 9 18 public class ReverseHighlighter extends DefaultHighlighter { 19 22 public ReverseHighlighter() { 23 drawsLayeredHighlights = true; 24 } 25 26 28 33 public void paint(Graphics g) { 34 int len = highlights.size(); 36 for (int i = 0; i < len; i++) { 37 HighlightInfo info = highlights.elementAt(i); 38 if (!(info instanceof LayeredHighlightInfo)) { 39 Rectangle a = component.getBounds(); 41 Insets insets = component.getInsets(); 42 a.x = insets.left; 43 a.y = insets.top; 44 a.width -= insets.left + insets.right; 45 a.height -= insets.top + insets.bottom; 46 for (; i < len; i++) { 47 info = highlights.elementAt(i); 48 if (! (info instanceof LayeredHighlightInfo)) { 49 Highlighter.HighlightPainter p = info.getPainter(); 50 p.paint(g, info.getStartOffset(), info.getEndOffset(), 51 a, component); 52 } 53 } 54 } 55 } 56 } 57 58 63 public void install(JTextComponent c) { 64 component = c; 65 removeAllHighlights(); 66 } 67 68 72 public void deinstall(JTextComponent c) { 73 component = null; 74 } 75 76 83 public Object addHighlight(int p0, int p1, Highlighter.HighlightPainter p) throws BadLocationException { 84 Document doc = component.getDocument(); 85 HighlightInfo i = (getDrawsLayeredHighlights() && 86 (p instanceof LayeredHighlighter.LayerPainter)) ? 87 new LayeredHighlightInfo() : new HighlightInfo(); 88 i.painter = p; 89 90 i.p0 = doc.createPosition(p0); 91 i.p1 = doc.createPosition(p1); 92 93 int insertPos = 0; 94 if ((!(p instanceof DefaultFrameHighlightPainter)) && (!(p instanceof DefaultUnderlineHighlightPainter))) { 95 for(HighlightInfo hli: highlights) { 97 if ((! (hli.getPainter() instanceof DefaultFrameHighlightPainter)) && 98 (! (hli.getPainter() instanceof DefaultUnderlineHighlightPainter))) { 99 break; 100 } 101 ++insertPos; 102 } 103 } 104 highlights.add(insertPos, i); 105 safeDamageRange(p0, p1); 106 return i; 107 } 108 109 114 public void removeHighlight(Object tag) { 115 if (tag instanceof LayeredHighlightInfo) { 116 LayeredHighlightInfo lhi = (LayeredHighlightInfo)tag; 117 if (lhi.width > 0 && lhi.height > 0) { 118 component.repaint(lhi.x, lhi.y, lhi.width, lhi.height); 119 } 120 } 121 else { 122 HighlightInfo info = (HighlightInfo) tag; 123 safeDamageRange(info.p0, info.p1); 124 } 125 highlights.removeElement(tag); 126 } 127 128 131 public void removeAllHighlights() { 132 TextUI mapper = component.getUI(); 133 if (getDrawsLayeredHighlights()) { 134 int len = highlights.size(); 135 if (len != 0) { 136 int minX = 0; 137 int minY = 0; 138 int maxX = 0; 139 int maxY = 0; 140 int p0 = -1; 141 int p1 = -1; 142 for (int i = 0; i < len; i++) { 143 HighlightInfo hi = highlights.elementAt(i); 144 if (hi instanceof LayeredHighlightInfo) { 145 LayeredHighlightInfo info = (LayeredHighlightInfo)hi; 146 minX = Math.min(minX, info.x); 147 minY = Math.min(minY, info.y); 148 maxX = Math.max(maxX, info.x + info.width); 149 maxY = Math.max(maxY, info.y + info.height); 150 } 151 else { 152 if (p0 == -1) { 153 p0 = hi.p0.getOffset(); 154 p1 = hi.p1.getOffset(); 155 } 156 else { 157 p0 = Math.min(p0, hi.p0.getOffset()); 158 p1 = Math.max(p1, hi.p1.getOffset()); 159 } 160 } 161 } 162 if (minX != maxX && minY != maxY) { 163 component.repaint(minX, minY, maxX - minX, maxY - minY); 164 } 165 if (p0 != -1) { 166 try { 167 safeDamageRange(p0, p1); 168 } catch (BadLocationException e) {} 169 } 170 highlights.removeAllElements(); 171 } 172 } 173 else if (mapper != null) { 174 int len = highlights.size(); 175 if (len != 0) { 176 int p0 = Integer.MAX_VALUE; 177 int p1 = 0; 178 for (int i = 0; i < len; i++) { 179 HighlightInfo info = highlights.elementAt(i); 180 p0 = Math.min(p0, info.p0.getOffset()); 181 p1 = Math.max(p1, info.p1.getOffset()); 182 } 183 try { 184 safeDamageRange(p0, p1); 185 } catch (BadLocationException e) {} 186 187 highlights.removeAllElements(); 188 } 189 } 190 } 191 192 200 public void changeHighlight(Object tag, int p0, int p1) throws BadLocationException { 201 Document doc = component.getDocument(); 202 if (tag instanceof LayeredHighlightInfo) { 203 LayeredHighlightInfo lhi = (LayeredHighlightInfo)tag; 204 if (lhi.width > 0 && lhi.height > 0) { 205 component.repaint(lhi.x, lhi.y, lhi.width, lhi.height); 206 } 207 lhi.width = lhi.height = 0; 210 211 lhi.p0 = doc.createPosition(p0); 212 lhi.p1 = doc.createPosition(p1); 213 safeDamageRange(Math.min(p0, p1), Math.max(p0, p1)); 214 } 215 else { 216 HighlightInfo info = (HighlightInfo) tag; 217 int oldP0 = info.p0.getOffset(); 218 int oldP1 = info.p1.getOffset(); 219 if (p0 == oldP0) safeDamageRange(Math.min(oldP1, p1), Math.max(oldP1, p1)); 220 else if (p1 == oldP1) safeDamageRange(Math.min(p0, oldP0), Math.max(p0, oldP0)); 221 else { 222 safeDamageRange(oldP0, oldP1); 223 safeDamageRange(p0, p1); 224 } 225 226 info.p0 = doc.createPosition(p0); 227 info.p1 = doc.createPosition(p1); 228 229 } 231 } 232 233 240 public Highlighter.Highlight[] getHighlights() { 241 int size = highlights.size(); 242 if (size == 0) { 243 return noHighlights; 244 } 245 Highlighter.Highlight[] h = new Highlighter.Highlight[size]; 246 highlights.copyInto(h); 247 return h; 248 } 249 250 262 public void paintLayeredHighlights(Graphics g, int p0, int p1, 263 Shape viewBounds, 264 JTextComponent editor, View view) { 265 for (int counter = highlights.size() - 1; counter >= 0; counter--) { 266 Object tag = highlights.elementAt(counter); 267 if (tag instanceof LayeredHighlightInfo) { 268 LayeredHighlightInfo lhi = (LayeredHighlightInfo)tag; 269 int start = lhi.getStartOffset(); 270 int end = lhi.getEndOffset(); 271 if ((p0 < start && p1 > start) || 272 (p0 >= start && p0 < end)) { 273 lhi.paintLayeredHighlights(g, p0, p1, viewBounds, 274 editor, view); 275 } 276 } 277 } 278 } 279 280 281 private void safeDamageRange(final Position p0, final Position p1) { 282 safeDamager.damageRange(p0, p1); 283 } 284 285 286 private void safeDamageRange(int a0, int a1) throws BadLocationException { 287 Document doc = component.getDocument(); 288 289 safeDamageRange(doc.createPosition(a0), doc.createPosition(a1)); 290 } 291 292 300 public void setDrawsLayeredHighlights(boolean newValue) { 301 drawsLayeredHighlights = newValue; 302 } 303 304 public boolean getDrawsLayeredHighlights() { 305 return drawsLayeredHighlights; 306 } 307 308 310 private final static Highlighter.Highlight[] noHighlights = 311 new Highlighter.Highlight[0]; 312 private Vector <HighlightInfo> highlights = new Vector <HighlightInfo>(); private JTextComponent component; 314 private boolean drawsLayeredHighlights; 315 private SafeDamager safeDamager = new SafeDamager(); 316 317 318 public static class DefaultFrameHighlightPainter extends LayeredHighlighter.LayerPainter { 319 320 327 public DefaultFrameHighlightPainter(Color c, int t) { 328 color = c; 329 thickness = t; 330 } 331 332 337 public Color getColor() { 338 return color; 339 } 340 341 342 public int getThickness() { return thickness; } 343 344 346 private void drawRectThick(Graphics g, int x, int y, int width, int height, int thick) { 347 if (thick<2) { g.drawRect(x, y, width, height); } 348 else { 349 g.fillRect(x, y, width, thick); 350 g.fillRect(x, y+height-thick, width, thick); 351 g.fillRect(x, y, thick, height); 352 g.fillRect(x+width-thick, y, thick, height); 353 } 354 } 355 356 365 public void paint(Graphics g, int offs0, int offs1, Shape bounds, JTextComponent c) { 366 Rectangle alloc = bounds.getBounds(); 367 try { 368 TextUI mapper = c.getUI(); 370 Rectangle p0 = mapper.modelToView(c, offs0); 371 Rectangle p1 = mapper.modelToView(c, offs1); 372 373 Color color = getColor(); 375 376 if (color == null) { 377 g.setColor(c.getSelectionColor()); 378 } 379 else { 380 g.setColor(color); 381 } 382 if (p0.y == p1.y) { 383 Rectangle r = p0.union(p1); 385 drawRectThick(g, r.x, r.y, r.width, r.height, thickness); 386 } else { 387 int p0ToMarginWidth = alloc.x + alloc.width - p0.x; 389 drawRectThick(g, p0.x, p0.y, p0ToMarginWidth, p0.height, thickness); 390 if ((p0.y + p0.height) != p1.y) { 391 drawRectThick(g, alloc.x, p0.y + p0.height, alloc.width, 392 p1.y - (p0.y + p0.height), thickness); 393 } 394 drawRectThick(g, alloc.x, p1.y, (p1.x - alloc.x), p1.height, thickness); 395 } 396 } catch (BadLocationException e) { 397 } 399 } 400 401 414 public Shape paintLayer(Graphics g, int offs0, int offs1, 415 Shape bounds, JTextComponent c, View view) { 416 Color color = getColor(); 417 418 if (color == null) { 419 g.setColor(c.getSelectionColor()); 420 } 421 else { 422 g.setColor(color); 423 } 424 if (offs0 == view.getStartOffset() && 425 offs1 == view.getEndOffset()) { 426 Rectangle alloc; 428 if (bounds instanceof Rectangle) { 429 alloc = (Rectangle)bounds; 430 } 431 else { 432 alloc = bounds.getBounds(); 433 } 434 drawRectThick(g, alloc.x, alloc.y, alloc.width, alloc.height, thickness); 435 return alloc; 436 } 437 else { 438 try { 440 Shape shape = view.modelToView(offs0, Position.Bias.Forward, 442 offs1,Position.Bias.Backward, 443 bounds); 444 Rectangle r = (shape instanceof Rectangle) ? 445 (Rectangle)shape : shape.getBounds(); 446 drawRectThick(g, r.x, r.y, r.width, r.height, thickness); 447 return r; 448 } catch (BadLocationException e) { 449 } 451 } 452 return null; 454 } 455 456 private Color color; 457 private int thickness; 458 } 459 460 461 464 public static class DefaultUnderlineHighlightPainter extends LayeredHighlighter.LayerPainter { 465 466 473 public DefaultUnderlineHighlightPainter(Color c, int t) { 474 color = c; 475 thickness = t; 476 } 477 478 483 public Color getColor() { 484 return color; 485 } 486 487 488 public int getThickness() { return thickness; } 489 490 492 private void drawUnderline(Graphics g, int x, int y, int width, int height, int thick) { 493 g.fillRect(x, y+height-thick, width, thick); 494 } 495 496 505 public void paint(Graphics g, int offs0, int offs1, Shape bounds, JTextComponent c) { 506 Rectangle alloc = bounds.getBounds(); 507 try { 508 TextUI mapper = c.getUI(); 510 Rectangle p0 = mapper.modelToView(c, offs0); 511 Rectangle p1 = mapper.modelToView(c, offs1); 512 513 Color color = getColor(); 515 516 if (color == null) { 517 g.setColor(c.getSelectionColor()); 518 } 519 else { 520 g.setColor(color); 521 } 522 if (p0.y == p1.y) { 523 Rectangle r = p0.union(p1); 525 drawUnderline(g, r.x, r.y, r.width, r.height, thickness); 526 } else { 527 int p0ToMarginWidth = alloc.x + alloc.width - p0.x; 529 drawUnderline(g, p0.x, p0.y, p0ToMarginWidth, p0.height, thickness); 530 if ((p0.y + p0.height) != p1.y) { 531 drawUnderline(g, alloc.x, p0.y + p0.height, alloc.width, 532 p1.y - (p0.y + p0.height), thickness); 533 } 534 drawUnderline(g, alloc.x, p1.y, (p1.x - alloc.x), p1.height, thickness); 535 } 536 } catch (BadLocationException e) { 537 } 539 } 540 541 554 public Shape paintLayer(Graphics g, int offs0, int offs1, 555 Shape bounds, JTextComponent c, View view) { 556 Color color = getColor(); 557 558 if (color == null) { 559 g.setColor(c.getSelectionColor()); 560 } 561 else { 562 g.setColor(color); 563 } 564 if (offs0 == view.getStartOffset() && 565 offs1 == view.getEndOffset()) { 566 Rectangle alloc; 568 if (bounds instanceof Rectangle) { 569 alloc = (Rectangle)bounds; 570 } 571 else { 572 alloc = bounds.getBounds(); 573 } 574 drawUnderline(g, alloc.x, alloc.y, alloc.width, alloc.height, thickness); 575 return alloc; 576 } 577 else { 578 try { 580 Shape shape = view.modelToView(offs0, Position.Bias.Forward, 582 offs1,Position.Bias.Backward, 583 bounds); 584 Rectangle r = (shape instanceof Rectangle) ? 585 (Rectangle)shape : shape.getBounds(); 586 drawUnderline(g, r.x, r.y, r.width, r.height, thickness); 587 return r; 588 } catch (BadLocationException e) { 589 } 591 } 592 return null; 594 } 595 596 private Color color; 597 private int thickness; 598 } 599 600 class HighlightInfo implements Highlighter.Highlight { 601 602 public int getStartOffset() { 603 return p0.getOffset(); 604 } 605 606 public int getEndOffset() { 607 return p1.getOffset(); 608 } 609 610 public Highlighter.HighlightPainter getPainter() { 611 return painter; 612 } 613 614 Position p0; 615 Position p1; 616 Highlighter.HighlightPainter painter; 617 } 618 619 620 624 class LayeredHighlightInfo extends HighlightInfo { 625 626 void union(Shape bounds) { 627 if (bounds == null) 628 return; 629 630 Rectangle alloc; 631 if (bounds instanceof Rectangle) { 632 alloc = (Rectangle)bounds; 633 } 634 else { 635 alloc = bounds.getBounds(); 636 } 637 if (width == 0 || height == 0) { 638 x = alloc.x; 639 y = alloc.y; 640 width = alloc.width; 641 height = alloc.height; 642 } 643 else { 644 width = Math.max(x + width, alloc.x + alloc.width); 645 height = Math.max(y + height, alloc.y + alloc.height); 646 x = Math.min(x, alloc.x); 647 width -= x; 648 y = Math.min(y, alloc.y); 649 height -= y; 650 } 651 } 652 653 654 void paintLayeredHighlights(Graphics g, int p0, int p1, 655 Shape viewBounds, JTextComponent editor, 656 View view) { 657 int start = getStartOffset(); 658 int end = getEndOffset(); 659 p0 = Math.max(start, p0); 661 p1 = Math.min(end, p1); 662 union(((LayeredHighlighter.LayerPainter)painter).paintLayer 665 (g, p0, p1, viewBounds, editor, view)); 666 } 667 668 int x; 669 int y; 670 int width; 671 int height; 672 } 673 674 675 679 class SafeDamager implements Runnable { 680 private Vector <Position> p0 = new Vector <Position>(10); 681 private Vector <Position> p1 = new Vector <Position>(10); 682 private Document lastDoc = null; 683 684 685 public synchronized void run() { 686 if (component != null) { 687 TextUI mapper = component.getUI(); 688 if (mapper != null && lastDoc == component.getDocument()) { 689 int len = p0.size(); 691 for (int i = 0; i < len; i++){ 692 mapper.damageRange(component, p0.get(i).getOffset(), p1.get(i).getOffset()); 693 } 694 } 695 } 696 p0.clear(); 697 p1.clear(); 698 699 lastDoc = null; 701 } 702 703 713 public synchronized void damageRange(Position pos0, Position pos1) { 714 if (component == null) { 715 p0.clear(); 716 lastDoc = null; 717 return; 718 } 719 720 boolean addToQueue = p0.isEmpty(); 721 Document curDoc = component.getDocument(); 722 if (curDoc != lastDoc) { 723 if (!p0.isEmpty()) { 724 p0.clear(); 725 p1.clear(); 726 } 727 lastDoc = curDoc; 728 } 729 p0.add(pos0); 730 p1.add(pos1); 731 732 if (addToQueue) { 733 SwingUtilities.invokeLater(this); 734 } 735 } 736 } 737 } 738 | Popular Tags |