1 19 20 package org.netbeans.editor; 21 22 import java.awt.Graphics ; 23 import java.awt.Font ; 24 import java.awt.Color ; 25 import java.awt.List ; 26 import java.beans.PropertyChangeEvent ; 27 import java.beans.PropertyChangeListener ; 28 import javax.swing.text.JTextComponent ; 29 import javax.swing.text.Position ; 30 import org.netbeans.editor.Annotations; 31 import java.awt.Graphics2D ; 32 import java.awt.AlphaComposite ; 33 import java.awt.Composite ; 34 import java.awt.Shape ; 35 import java.awt.Rectangle ; 36 import javax.swing.text.View ; 37 38 47 interface DrawGraphics { 48 49 50 public void setForeColor(Color foreColor); 51 52 53 public void setBackColor(Color backColor); 54 55 58 public void setDefaultBackColor(Color defaultBackColor); 59 60 public void setStrikeThroughColor(Color strikeThroughColor); 61 62 public void setUnderlineColor(Color underlineColor); 63 64 public void setWaveUnderlineColor(Color waveUnderlineColor); 65 66 67 public void setFont(Font font); 68 69 70 public void setX(int x); 71 72 73 public void setY(int y); 74 75 76 public void setLineHeight(int lineHeight); 77 78 79 public void setLineAscent(int lineAscent); 80 81 84 public Graphics getGraphics(); 85 86 89 public boolean supportsLineNumbers(); 90 91 92 public void init(DrawContext ctx); 93 94 97 public void finish(); 98 99 104 public void fillRect(int width); 105 106 114 public void drawChars(int offset, int length, int width); 115 116 123 public void drawTabs(int offset, int length, int spaceCount, int width); 124 125 126 public void setBuffer(char[] buffer); 127 128 145 public boolean targetOffsetReached(int offset, char ch, int x, 146 int charWidth, DrawContext ctx); 147 148 149 public void eol(); 150 151 152 public void setView(javax.swing.text.View view); 153 154 155 158 static abstract class AbstractDG implements DrawGraphics { 159 160 161 Color foreColor; 162 163 164 Color backColor; 165 166 167 Color defaultBackColor; 168 169 170 Font font; 171 172 173 char[] buffer; 174 175 176 int x; 177 178 179 int y; 180 181 182 int lineHeight; 183 184 185 int lineAscent; 186 187 public Color getForeColor() { 188 return foreColor; 189 } 190 191 public void setForeColor(Color foreColor) { 192 this.foreColor = foreColor; 193 } 194 195 public Color getBackColor() { 196 return backColor; 197 } 198 199 public void setBackColor(Color backColor) { 200 this.backColor = backColor; 201 } 202 203 public Color getDefaultBackColor() { 204 return defaultBackColor; 205 } 206 207 public void setDefaultBackColor(Color defaultBackColor) { 208 this.defaultBackColor = defaultBackColor; 209 } 210 211 public Font getFont() { 212 return font; 213 } 214 215 public void setFont(Font font) { 216 this.font = font; 217 } 218 219 public int getX() { 220 return x; 221 } 222 223 public void setX(int x) { 224 this.x = x; 225 } 226 227 public int getY() { 228 return y; 229 } 230 231 public void setY(int y) { 232 this.y = y; 233 } 234 235 public int getLineHeight() { 236 return lineHeight; 237 } 238 239 public void setLineHeight(int lineHeight) { 240 this.lineHeight = lineHeight; 241 } 242 243 public int getLineAscent() { 244 return lineAscent; 245 } 246 247 public void setLineAscent(int lineAscent) { 248 this.lineAscent = lineAscent; 249 } 250 251 public char[] getBuffer() { 252 return buffer; 253 } 254 255 public void setBuffer(char[] buffer) { 256 this.buffer = buffer; 257 } 258 259 public void drawChars(int offset, int length, int width) { 260 x += width; 261 } 262 263 public void drawTabs(int offset, int length, int spaceCount, int width) { 264 x += width; 265 } 266 267 public void setStrikeThroughColor(Color strikeThroughColor) { 268 } 269 270 public void setUnderlineColor(Color underlineColor) { 271 } 272 273 public void setWaveUnderlineColor(Color waveUnderlineColor) { 274 } 275 276 public void setView(javax.swing.text.View view) { 277 } 278 279 } 280 281 static class SimpleDG extends AbstractDG { 282 283 public Graphics getGraphics() { 284 return null; 285 } 286 287 public boolean supportsLineNumbers() { 288 return false; 289 } 290 291 public void init(DrawContext ctx) { 292 } 293 294 public void finish() { 295 } 296 297 public void fillRect(int width) { 298 } 299 300 public boolean targetOffsetReached(int offset, char ch, int x, 301 int charWidth, DrawContext ctx) { 302 return true; } 304 305 public void eol() { 306 } 307 308 } 309 310 314 static final class GraphicsDG extends SimpleDG { 315 316 317 private static final boolean debug 318 = Boolean.getBoolean("netbeans.debug.editor.draw.graphics"); 320 private Graphics graphics; 321 322 325 private int startOffset = -1; 326 327 328 private int endOffset; 329 330 331 private int startX; 332 333 334 private int startY; 335 336 private int width; 337 338 private Color strikeThroughColor; 339 340 private Color underlineColor; 341 342 private Color waveUnderlineColor; 343 344 345 private int lastDrawnAnnosY; 346 private int lastDrawnAnnosX; 347 348 349 private AnnotationDesc[] passiveAnnosAtY; 350 351 352 private AlphaComposite alpha = null; 353 354 356 private Annotations annos = null; 357 358 private boolean drawTextLimitLine; 359 private int textLimitWidth; 360 private int defaultSpaceWidth; 361 private Color textLimitLineColor; 362 private int absoluteX; 363 private int maxWidth; 364 private View view; 365 366 private int bufferStartOffset; 367 private int frameStartOffset = Integer.MAX_VALUE; 368 private int frameEndOffset = frameStartOffset; 369 private JTextComponent component; 370 private PropertyChangeListener componentListener; 371 372 GraphicsDG(Graphics graphics) { 373 this.graphics = graphics; 374 this.y = -1; 376 } 377 378 public void setForeColor(Color foreColor) { 379 if (!foreColor.equals(this.foreColor)) { 380 flush(); 381 this.foreColor = foreColor; 382 } 383 } 384 385 public void setBackColor(Color backColor) { 386 if (!backColor.equals(this.backColor)) { 387 flush(); 388 this.backColor = backColor; 389 } 390 } 391 392 public void setStrikeThroughColor(Color strikeThroughColor) { 393 if ((strikeThroughColor != this.strikeThroughColor) 394 && (strikeThroughColor == null 395 || !strikeThroughColor.equals(this.strikeThroughColor)) 396 ) { 397 flush(); 398 this.strikeThroughColor = strikeThroughColor; 399 } 400 } 401 402 public void setUnderlineColor(Color underlineColor) { 403 if ((underlineColor != this.underlineColor) 404 && (underlineColor == null 405 || !underlineColor.equals(this.underlineColor)) 406 ) { 407 flush(); 408 this.underlineColor = underlineColor; 409 } 410 } 411 412 public void setWaveUnderlineColor(Color waveUnderlineColor) { 413 if ((waveUnderlineColor != this.waveUnderlineColor) 414 && (waveUnderlineColor == null 415 || !waveUnderlineColor.equals(this.waveUnderlineColor)) 416 ) { 417 flush(); 418 this.waveUnderlineColor = waveUnderlineColor; 419 } 420 } 421 422 public void setFont(Font font) { 423 if (!font.equals(this.font)) { 424 flush(); 425 this.font = font; 426 } 427 } 428 429 public void setX(int x) { 430 if (x != this.x) { 431 flush(); 432 this.x = x; 433 } 434 } 435 436 public void setY(int y) { 437 if (y != this.y) { 438 flush(); 439 this.y = y; 440 } 441 } 442 443 public void init(DrawContext ctx) { 444 component = ctx.getEditorUI().getComponent(); 445 annos = ctx.getEditorUI().getDocument().getAnnotations(); 447 drawTextLimitLine = ctx.getEditorUI().textLimitLineVisible; 448 textLimitWidth = ctx.getEditorUI().textLimitWidth; 449 defaultSpaceWidth = ctx.getEditorUI().defaultSpaceWidth; 450 textLimitLineColor = ctx.getEditorUI().textLimitLineColor; 451 absoluteX = ctx.getEditorUI().getTextMargin().left; 452 maxWidth = ctx.getEditorUI().getExtentBounds().width; 453 454 componentListener = new PropertyChangeListener () { 455 public void propertyChange(PropertyChangeEvent evt) { 456 if (DrawLayer.TEXT_FRAME_START_POSITION_COMPONENT_PROPERTY.equals(evt.getPropertyName())) { 457 if (evt.getNewValue() instanceof Position ) { 458 frameStartOffset = ((Position )evt.getNewValue()).getOffset(); 459 } else { 460 frameStartOffset = Integer.MAX_VALUE; 461 } 462 } 463 if (DrawLayer.TEXT_FRAME_END_POSITION_COMPONENT_PROPERTY.equals(evt.getPropertyName())) { 464 if (evt.getNewValue() instanceof Position ) { 465 frameEndOffset = ((Position )evt.getNewValue()).getOffset(); 466 } else { 467 frameEndOffset = Integer.MAX_VALUE; 468 } 469 } 470 } 471 }; 472 component.addPropertyChangeListener(componentListener); 473 } 474 475 public void finish() { 476 if (component != null) { 480 component.removePropertyChangeListener(componentListener); 481 } 482 } 483 484 public void setView(View view){ 485 this.view = view; 486 } 487 488 private void flush() { 489 flush(false); 490 } 491 492 493 private void flush(boolean atEOL) { 494 if (y < 0) { return ; 496 } 497 498 if (startOffset >= 0 && startOffset != endOffset) { fillRectImpl(startX, startY, x - startX); 501 } 502 503 if (lastDrawnAnnosY != y) { 506 lastDrawnAnnosY = y; 507 lastDrawnAnnosX = 0; 508 if (AnnotationTypes.getTypes().isBackgroundDrawing().booleanValue()) { 509 if (alpha == null) 510 alpha = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, AnnotationTypes.getTypes().getBackgroundGlyphAlpha().intValue() / 100f); 511 if (view!=null){ 512 passiveAnnosAtY = annos.getPassiveAnnotations(view.getStartOffset()); 513 } 514 } else { 515 passiveAnnosAtY = null; 516 } 517 } 518 519 int glyphX=2; 520 if (passiveAnnosAtY != null) { 521 Graphics2D g2d = (Graphics2D ) graphics; 522 523 Shape shape = graphics.getClip(); 524 525 Composite origin = g2d.getComposite(); 527 g2d.setComposite(alpha); 528 529 int endX = atEOL ? Integer.MAX_VALUE : x; 531 int startX = Math.min(lastDrawnAnnosX, this.startX); 532 Rectangle r = new Rectangle (startX, y, endX - startX, lineHeight); 533 lastDrawnAnnosX = endX; 534 r = r.intersection(shape.getBounds()); 535 graphics.setClip(r); 536 537 for (int i=0; i < passiveAnnosAtY.length; i++) { 538 g2d.drawImage(passiveAnnosAtY[i].getGlyph(), glyphX, y, null); 539 glyphX += passiveAnnosAtY[i].getGlyph().getWidth(null)+1; 540 } 541 542 graphics.setClip(shape); 544 545 g2d.setComposite(origin); 547 } 548 549 if (startOffset < 0 || startOffset >= endOffset || endOffset > buffer.length) { 551 startOffset = -1; 552 return; 553 } 554 555 556 if (drawTextLimitLine) { Rectangle clip = graphics.getClipBounds(); 558 int lineX = absoluteX + textLimitWidth * defaultSpaceWidth; 559 if (lineX >= startX && lineX <= x){ 560 Color bakColor = graphics.getColor(); 561 graphics.setColor(textLimitLineColor); 562 graphics.drawLine(lineX, startY, lineX, startY + lineHeight); 563 graphics.setColor(bakColor); 564 } 565 } 566 567 if (frameStartOffset != Integer.MAX_VALUE && bufferStartOffset != -1) { 569 if (bufferStartOffset + startOffset == frameStartOffset) { graphics.drawLine(startX, startY, startX, startY + lineHeight); 571 } 572 if (bufferStartOffset + startOffset >= frameStartOffset 573 && bufferStartOffset + endOffset <= frameEndOffset 574 ) { 575 graphics.drawLine(startX, startY, x, startY); 576 graphics.drawLine(startX, startY, x, startY + lineHeight); 577 } 578 if (bufferStartOffset + endOffset == frameEndOffset) { graphics.drawLine(x, startY, x, startY + lineHeight); 580 } 581 } 582 583 graphics.setColor(foreColor); 585 graphics.setFont(font); 587 588 if (debug) { 589 String text = new String (buffer, startOffset, endOffset - startOffset); 590 System.out.println("DrawGraphics: text='" + text + "', text.length=" + text.length() + ", x=" + startX + ", y=" + startY + ", ascent=" + lineAscent + ", clip=" + graphics.getClipBounds() + ", color=" + graphics.getColor() ); 597 } 598 599 graphics.drawChars(buffer, startOffset, endOffset - startOffset, 600 startX, startY + lineAscent); 601 602 if (strikeThroughColor != null) { FontMetricsCache.Info fmcInfo = FontMetricsCache.getInfo(font); 604 graphics.setColor(strikeThroughColor); 605 graphics.fillRect(startX, 606 (int)(startY + fmcInfo.getStrikethroughOffset(graphics) + lineAscent + 1.5), 607 x - startX, 608 (int)(fmcInfo.getStrikethroughThickness(graphics) + 0.5) 609 ); 610 } 611 612 if (waveUnderlineColor != null) { FontMetricsCache.Info fmcInfo = FontMetricsCache.getInfo(font); 614 graphics.setColor(waveUnderlineColor); 615 616 int waveLength = x - startX; 617 if (waveLength > 0) { 618 int[] wf = {0, +1, 0, -1}; 619 int[] xArray = new int[waveLength + 1]; 620 int[] yArray = new int[waveLength + 1]; 621 622 int yBase = (int)(startY + fmcInfo.getUnderlineOffset(graphics) + lineAscent + 1.5); 623 for (int i=0;i<=waveLength;i++) { 624 xArray[i]=startX + i; 625 yArray[i]=yBase + wf[xArray[i] % 4]; 626 } 627 graphics.drawPolyline(xArray, yArray, waveLength); 628 } 629 } 630 631 if (underlineColor != null) { FontMetricsCache.Info fmcInfo = FontMetricsCache.getInfo(font); 633 graphics.setColor(underlineColor); 634 graphics.fillRect(startX, 635 (int)(startY + fmcInfo.getUnderlineOffset(graphics) + lineAscent + 1.5), 636 x - startX, 637 (int) (fmcInfo.getUnderlineThickness(graphics) + 0.5) 638 ); 639 } 640 641 startOffset = -1; } 643 644 public Graphics getGraphics() { 645 return graphics; 646 } 647 648 public boolean supportsLineNumbers() { 649 return true; 650 } 651 652 public void fillRect(int width) { 653 fillRectImpl(x, y, width); 654 x += width; 655 } 656 657 private void fillRectImpl(int rx, int ry, int width) { 658 if (width > 0) { if (!backColor.equals(defaultBackColor)) { 661 graphics.setColor(backColor); 662 graphics.fillRect(rx, ry, width, lineHeight); 663 } 664 665 } 666 } 667 668 669 public void drawChars(int offset, int length, int width) { 670 if (length >= 0) { 671 if (startOffset < 0) { startOffset = offset; 673 endOffset = offset + length; 674 this.startX = x; 675 this.startY = y; 676 this.width = width; 677 678 } else { endOffset += length; 680 } 681 } 682 683 x += width; 684 } 685 686 public void drawTabs(int offset, int length, int spaceCount, int width) { 687 if (width > 0) { 688 flush(); 689 fillRectImpl(x, y, width); 690 x += width; 691 } 692 } 693 694 public void setBuffer(char[] buffer) { 695 flush(); 696 this.buffer = buffer; 697 startOffset = -1; 698 bufferStartOffset = -1; 699 } 700 701 void setBufferStartOffset(int bufferStartOffset) { 702 this.bufferStartOffset = bufferStartOffset; 703 } 704 705 public void eol() { 706 if (drawTextLimitLine) { int lineX = absoluteX + textLimitWidth * defaultSpaceWidth; 708 if (lineX >= x-defaultSpaceWidth){ 709 Color bakColor = graphics.getColor(); 710 graphics.setColor(textLimitLineColor); 711 Rectangle clipB = graphics.getClipBounds(); 712 if (clipB.width + clipB.x <= lineX){ 713 graphics.setClip(clipB.x, clipB.y, maxWidth, clipB.height); 714 graphics.drawLine(lineX, y, lineX, y + lineHeight); 715 graphics.setClip(clipB.x, clipB.y, clipB.width, clipB.height); 716 }else{ 717 graphics.drawLine(lineX, y, lineX, y + lineHeight); 718 } 719 graphics.setColor(bakColor); 720 } 721 } 722 flush(true); 723 } 724 725 } 726 727 static final class PrintDG extends SimpleDG { 728 729 PrintContainer container; 730 731 732 boolean lineInited; 733 734 738 public PrintDG(PrintContainer container) { 739 this.container = container; 740 } 741 742 public boolean supportsLineNumbers() { 743 return true; 744 } 745 746 public void drawChars(int offset, int length, int width) { 747 if (length > 0) { 748 lineInited = true; char[] chars = new char[length]; 750 System.arraycopy(buffer, offset, chars, 0, length); 751 container.add(chars, font, foreColor, backColor); 752 } 753 } 754 755 private void printSpaces(int spaceCount) { 756 char[] chars = new char[spaceCount]; 757 System.arraycopy(Analyzer.getSpacesBuffer(spaceCount), 0, chars, 0, spaceCount); 758 container.add(chars, font, foreColor, backColor); 759 } 760 761 public void drawTabs(int offset, int length, int spaceCount, int width) { 762 lineInited = true; printSpaces(spaceCount); 764 } 765 766 public void eol() { 767 if (!lineInited && container.initEmptyLines()) { 768 printSpaces(1); 769 } 770 container.eol(); 771 lineInited = false; } 773 774 } 775 776 } 777 | Popular Tags |