1 19 package org.netbeans.core.output2; 20 21 import java.util.HashMap ; 22 import java.util.Map ; 23 24 import javax.swing.*; 25 import javax.swing.text.*; 26 import java.awt.*; 27 import org.openide.util.Exceptions; 28 29 42 public class WrappedTextView extends View { 43 46 private JTextComponent comp; 47 50 private int charsPerLine = -1; 51 55 private int fontDescent = -1; 56 59 private static final Segment SEGMENT = new Segment(); 60 63 private int width = -1; 64 67 private boolean changed = true; 68 71 private int charWidth = -1; 72 75 private int charHeight = -1; 76 79 static final int[] ln = new int[3]; 80 84 private boolean aa = false; 85 86 private static final boolean antialias = Boolean.getBoolean ("swing.aatext") || "Aqua".equals (UIManager.getLookAndFeel().getID()); 89 static Color selectedFg; 91 static Color unselectedFg; 92 static Color selectedLinkFg; 93 static Color unselectedLinkFg; 94 static Color selectedImportantLinkFg; 95 static Color unselectedImportantLinkFg; 96 static Color selectedErr; 97 static Color unselectedErr; 98 static final Color arrowColor = new Color (80, 162, 80); 99 100 private static Map hintsMap = null; 101 102 static final Map getHints() { 103 if (hintsMap == null) { 104 hintsMap = (Map )(Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints")); if (hintsMap == null) { 107 hintsMap = new HashMap (); 108 if (antialias) { 109 hintsMap.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); 110 hintsMap.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 111 } 112 } 113 } 114 return hintsMap; 115 } 116 117 static { 118 selectedFg = UIManager.getColor ("nb.output.foreground.selected"); if (selectedFg == null) { 120 selectedFg = UIManager.getColor("textText") == null ? Color.BLACK : UIManager.getColor("textText"); } 123 124 unselectedFg = UIManager.getColor ("nb.output.foreground"); if (unselectedFg == null) { 126 unselectedFg = selectedFg; 127 } 128 129 selectedLinkFg = UIManager.getColor("nb.output.link.foreground.selected"); if (selectedLinkFg == null) selectedLinkFg = Color.BLUE.darker(); 131 132 unselectedLinkFg = UIManager.getColor("nb.output.link.foreground"); if (unselectedLinkFg == null) { 134 unselectedLinkFg = selectedLinkFg; 135 } 136 137 selectedImportantLinkFg = UIManager.getColor("nb.output.link.foreground.important.selected"); if (selectedImportantLinkFg == null) { 139 selectedImportantLinkFg = selectedLinkFg.brighter(); 140 } 141 142 unselectedImportantLinkFg = UIManager.getColor("nb.output.link.foreground.important"); if (unselectedImportantLinkFg == null) { 144 unselectedImportantLinkFg = selectedImportantLinkFg; 145 } 146 147 selectedErr = UIManager.getColor ("nb.output.err.foreground.selected"); if (selectedErr == null) { 149 selectedErr = new Color (164, 0, 0); 150 } 151 unselectedErr = UIManager.getColor ("nb.output.err.foreground"); if (unselectedErr == null) { 153 unselectedErr = selectedErr; 154 } 155 } 156 157 158 public WrappedTextView(Element elem, JTextComponent comp) { 159 super(elem); 160 this.comp = comp; 161 } 162 163 164 public float getPreferredSpan(int axis) { 165 OutputDocument doc = odoc(); 166 float result = 0; 167 if (doc != null) { 168 switch (axis) { 169 case X_AXIS : 170 result = getCharsPerLine(); 171 break; 172 case Y_AXIS : 173 updateInfo(null); 174 result = doc.getLines().getLogicalLineCountIfWrappedAt(getCharsPerLine()) * charHeight() + fontDescent(); 175 break; 176 default : 177 throw new IllegalArgumentException (Integer.toString(axis)); 178 } 179 } 180 return result; 181 } 182 183 public float getMinimumSpan(int axis) { 184 return getPreferredSpan(axis); 185 } 186 187 public float getMaximumSpan(int axis) { 188 return getPreferredSpan(axis); 189 } 190 191 197 private int charWidth() { 198 if (charWidth == -1) { 199 return 12; 200 } 201 return charWidth; 202 } 203 204 210 private int charHeight() { 211 if (charHeight == -1) { 212 return 7; 213 } 214 return charHeight; 215 } 216 217 224 private OutputDocument odoc() { 225 Document doc = comp.getDocument(); 226 if (doc instanceof OutputDocument) { 227 return (OutputDocument) doc; 228 } 229 return null; 230 } 231 232 237 public void setChanged() { 238 changed = true; 239 updateInfo (null); 240 preferenceChanged(this, true, true); 241 } 242 243 249 private int getCharsPerLine() { 250 if (charsPerLine == -1) { 251 return 80; 252 } 253 return getWidth() / charWidth(); 254 } 255 256 261 private int getWidth() { 262 if (comp.getParent() instanceof JViewport) { 263 JViewport jv = (JViewport) comp.getParent(); 264 width = jv.getExtentSize().width - (aa ? 18 : 17); 265 } else { 266 width = comp.getWidth() - (aa ? 18 : 17); 267 } 268 return width; 269 } 270 271 279 private int fontDescent() { 280 if (fontDescent == -1) { 281 return 4; 282 } 283 return fontDescent; 284 } 285 286 291 public void updateInfo(Graphics g) { 292 if (charWidth == -1 || changed) { 293 if (g != null) { 294 aa = ((Graphics2D) g).getRenderingHint(RenderingHints.KEY_ANTIALIASING) == 295 RenderingHints.VALUE_ANTIALIAS_ON; 296 297 FontMetrics fm = g.getFontMetrics(comp.getFont()); 298 charWidth = fm.charWidth('m'); charHeight = fm.getHeight(); 300 fontDescent = fm.getMaxDescent(); 301 charsPerLine = width / charWidth; 302 } 303 if (comp.getParent() instanceof JViewport) { 304 JViewport jv = (JViewport) comp.getParent(); 305 width = jv.getExtentSize().width - (aa ? 18 : 17); 306 } else { 307 width = comp.getWidth() - (aa ? 18 : 17); 308 } 309 } 310 } 311 312 317 private static int margin() { 318 return 9; 319 } 320 321 public void paint(Graphics g, Shape allocation) { 322 323 ((Graphics2D)g).addRenderingHints(getHints()); 324 325 updateInfo(g); 326 327 comp.getHighlighter().paint(g); 328 329 Rectangle vis = comp.getVisibleRect(); 330 331 OutputDocument d = odoc(); 332 if (d != null) { 333 Rectangle clip = g.getClipBounds(); 334 clip.y = Math.max (0, clip.y - charHeight()); 335 clip.height += charHeight() * 2; 336 337 int lineCount = d.getElementCount(); 338 if (lineCount == 0) { 339 return; 340 } 341 342 int charsPerLine = getCharsPerLine(); 343 int physicalLine = clip.y / charHeight; 344 ln[0] = physicalLine; 345 d.getLines().toLogicalLineIndex(ln, charsPerLine); 346 347 int firstline = ln[0]; 348 int count = (lineCount - firstline); 349 g.setColor (comp.getForeground()); 350 Segment seg = SwingUtilities.isEventDispatchThread() ? SEGMENT : new Segment(); 351 352 int selStart = comp.getSelectionStart(); 353 int selEnd = comp.getSelectionEnd(); 354 int y = (clip.y - (clip.y % charHeight()) + charHeight()); 355 356 try { 357 for (int i=0; i < count; i++) { 358 int lineStart = d.getLineStart(i + firstline); 359 int lineEnd = d.getLineEnd (i + firstline); 360 int length = lineEnd - lineStart; 361 362 g.setColor(getColorForLocation(lineStart, d, true)); 364 d.getText(lineStart, length, seg); 366 367 int logicalLines = seg.count <= charsPerLine ? 1 : 1 + (length / charsPerLine); 369 370 int currLogicalLine = 0; 371 372 if (i == 0 && logicalLines > 0) { 373 while (ln[1] > currLogicalLine) { 374 currLogicalLine++; 377 drawArrow (g, y - ((logicalLines - currLogicalLine) * charHeight()), currLogicalLine == ln[1]); 378 } 379 } 380 for (; currLogicalLine < logicalLines; currLogicalLine++) { 382 int charpos = currLogicalLine * charsPerLine; 383 int lenToDraw = Math.min(charsPerLine, length - charpos); 384 if (lenToDraw <= 0) { 385 break; 386 } 387 drawLogicalLine(seg, currLogicalLine, logicalLines, g, y, lineStart, charpos, selStart, lenToDraw, selEnd); 388 if (g.getColor() == unselectedLinkFg || g.getColor() == unselectedImportantLinkFg) { 389 underline(g, seg, charpos, lenToDraw, currLogicalLine, y); 390 } 391 y += charHeight(); 392 } 393 if (y > clip.y + clip.height || i + firstline == lineCount -1) { 394 break; 395 } 396 } 397 } catch (BadLocationException e) { 398 Exceptions.printStackTrace(e); 399 } 400 } 401 } 402 403 417 private void drawLogicalLine(Segment seg, int currLogicalLine, int logicalLines, Graphics g, int y, int lineStart, int charpos, int selStart, int lenToDraw, int selEnd) { 418 if (currLogicalLine != logicalLines-1) { 419 drawArrow (g, y, currLogicalLine == logicalLines-2); 420 } 421 int realPos = lineStart + charpos; 422 423 if (realPos >= selStart && realPos + lenToDraw <= selEnd) { 424 Color c = g.getColor(); 425 g.setColor (comp.getSelectionColor()); 426 g.fillRect (margin(), y+fontDescent()-charHeight(), lenToDraw * charWidth(), charHeight()); 427 g.setColor (c); 428 } else if (realPos <= selStart && realPos + lenToDraw >= selStart) { 429 int selx = margin() + (charWidth() * (selStart - realPos)); 430 int selLen = selEnd > realPos + lenToDraw ? ((lenToDraw + realPos) - selStart) * charWidth() : 431 (selEnd - selStart) * charWidth(); 432 Color c = g.getColor(); 433 g.setColor (comp.getSelectionColor()); 434 g.fillRect (selx, y + fontDescent() - charHeight(), selLen, charHeight()); 435 g.setColor (c); 436 } else if (realPos > selStart && realPos + lenToDraw >= selEnd) { 437 int selLen = (selEnd - realPos) * charWidth(); 439 Color c = g.getColor(); 440 g.setColor (comp.getSelectionColor()); 441 g.fillRect (margin(), y + fontDescent() - charHeight(), selLen, charHeight()); 442 g.setColor (c); 443 } 444 g.drawChars(seg.array, charpos, lenToDraw, margin(), y); 445 } 446 447 448 private void underline(Graphics g, Segment seg, int charpos, int lenToDraw, int currLogicalLine, int y) { 449 int underlineStart = margin(); 450 int underlineEnd = underlineStart + g.getFontMetrics().charsWidth(seg.array, charpos, lenToDraw); 451 if (currLogicalLine == 0) { 452 for (int k=1; k < lenToDraw; k++) { 455 if (Character.isWhitespace(seg.array[charpos + k])) { 456 underlineStart += charWidth(); 457 underlineEnd -= charWidth(); 458 } else { 459 break; 460 } 461 } 462 } else { 463 underlineStart = margin(); 464 } 465 g.drawLine (underlineStart, y+1, underlineEnd, y+1); 466 } 467 468 474 private void drawArrow (Graphics g, int y, boolean drawHead) { 475 int fontHeight = charHeight(); 476 Color c = g.getColor(); 477 478 g.setColor (arrowColor()); 479 480 int w = getWidth() + 15; 481 y+=2; 482 483 484 int rpos = aa ? 8 : 4; 485 if (aa) { 486 g.drawArc(w - rpos, y - (fontHeight / 2), rpos + 1, fontHeight, 265, 185); 487 } else { 488 g.drawLine (w-rpos, y - (fontHeight / 2), w, y - (fontHeight / 2)); 489 g.drawLine (w, y - (fontHeight / 2)+1, w, y + (fontHeight / 2) - 1); 490 g.drawLine (w-rpos, y + (fontHeight / 2), w, y + (fontHeight / 2)); 491 } 492 if (aa) { 493 w++; 494 } 495 if (drawHead) { 496 rpos = aa ? 7 : 8; 497 int[] xpoints = new int[] { 498 w - rpos, 499 w - rpos + 5, 500 w - rpos + 5, 501 }; 502 int[] ypoints = new int[] { 503 y + (fontHeight / 2), 504 y + (fontHeight / 2) - 5, 505 y + (fontHeight / 2) + 5, 506 }; 507 g.fillPolygon(xpoints, ypoints, 3); 508 } 509 510 g.setColor (arrowColor()); 511 g.drawLine (1, y - (fontHeight / 2), 5, y - (fontHeight / 2)); 512 g.drawLine (1, y - (fontHeight / 2), 1, y + (fontHeight / 2)); 513 g.drawLine (1, y + (fontHeight / 2), 5, y + (fontHeight / 2)); 514 515 g.setColor (c); 516 517 } 518 519 524 private static Color arrowColor() { 525 return arrowColor; 526 } 527 528 public Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException { 529 Rectangle result = new Rectangle(); 530 result.setBounds (0, 0, charWidth(), charHeight()); 531 OutputDocument od = odoc(); 532 if (od != null) { 533 int line = od.getElementIndex(pos); 534 int start = od.getLineStart(line); 535 536 int column = pos - start; 537 538 int charsPerLine = getCharsPerLine(); 539 540 int row = od.getLines().getLogicalLineCountAbove(line, charsPerLine); 541 if (column > charsPerLine) { 542 row += (column / charsPerLine); 543 column %= charsPerLine; 544 } 545 result.y = (row * charHeight()) + fontDescent(); 546 result.x = margin() + (column * charWidth()); 547 } 549 550 return result; 551 } 552 553 public int viewToModel(float x, float y, Shape a, Position.Bias[] biasReturn) { 554 OutputDocument od = odoc(); 555 if (od != null) { 556 int ix = (int) x - margin(); 557 int iy = (int) y - fontDescent(); 558 559 int charsPerLine = getCharsPerLine(); 560 561 int physicalLine = (iy / charHeight); 562 563 ln[0] = physicalLine; 564 od.getLines().toLogicalLineIndex(ln, charsPerLine); 565 int logicalLine = ln[0]; 566 int wraps = ln[2] - 1; 567 568 int totalLines = od.getElementCount(); 569 if (totalLines == 0) { 570 return 0; 571 } 572 if (logicalLine >= totalLines) { 573 return od.getLength() - 1; 574 } 575 576 int lineStart = od.getLineStart(logicalLine); 577 int lineLength = od.getLines().length(logicalLine); 578 579 int column = (ix / charWidth()); 580 if (column > lineLength-1) { 581 column = lineLength-1; 582 } 583 584 return wraps > 0 ? 585 Math.min(od.getLineEnd(logicalLine) - 1, lineStart + (ln[1] * charsPerLine) + column) 586 : lineStart + column; 587 592 } else { 593 return 0; 594 } 595 } 596 597 607 private static Color getColorForLocation (int start, Document d, boolean selected) { 608 OutputDocument od = (OutputDocument) d; 609 int line = od.getElementIndex (start); 610 boolean hyperlink = od.getLines().isHyperlink(line); 611 boolean important = hyperlink ? od.getLines().isImportantHyperlink(line) : false; 612 boolean isErr = od.getLines().isErr(line); 613 return hyperlink ? (important ? (selected ? selectedImportantLinkFg : unselectedImportantLinkFg) : 614 (selected ? selectedLinkFg : unselectedLinkFg)) : 615 (selected ? (isErr ? selectedErr : selectedFg) : 616 (isErr ? unselectedErr : unselectedFg)); 617 } 618 } 619 | Popular Tags |