1 19 24 25 package org.netbeans.core.output2.ui; 26 27 import java.awt.Rectangle ; 28 import javax.swing.plaf.TextUI ; 29 30 import javax.swing.*; 31 import javax.swing.event.ChangeEvent ; 32 import javax.swing.event.ChangeListener ; 33 import javax.swing.event.DocumentEvent ; 34 import javax.swing.event.DocumentListener ; 35 import javax.swing.text.*; 36 import java.awt.*; 37 import java.awt.event.*; 38 import org.openide.util.Exceptions; 39 40 49 public abstract class AbstractOutputPane extends JScrollPane implements DocumentListener , MouseListener, MouseMotionListener, KeyListener, ChangeListener , MouseWheelListener, Runnable { 50 private boolean locked = true; 51 52 private int fontHeight = -1; 53 private int fontWidth = -1; 54 protected JEditorPane textView; 55 int lastCaretLine = 0; 56 boolean hadSelection = false; 57 boolean recentlyReset = false; 58 59 public AbstractOutputPane() { 60 textView = createTextView(); 61 init(); 62 } 63 64 public void requestFocus() { 65 textView.requestFocus(); 66 } 67 68 public boolean requestFocusInWindow() { 69 return textView.requestFocusInWindow(); 70 } 71 72 protected abstract JEditorPane createTextView(); 73 74 protected void documentChanged() { 75 lastLength = -1; 76 if (pendingCaretLine != -1) { 77 if (!sendCaretToLine (pendingCaretLine, pendingCaretSelect)) { 78 ensureCaretPosition(); 79 } 80 } else { 81 ensureCaretPosition(); 82 } 83 if (recentlyReset && isShowing()) { 84 recentlyReset = false; 85 } 86 if (locked) { 87 setMouseLine(-1); 88 } 89 if (isWrapped()) { 90 getViewport().revalidate(); 92 getViewport().repaint(); 93 } 94 } 95 96 public abstract boolean isWrapped(); 97 public abstract void setWrapped (boolean val); 98 99 public boolean hasSelection() { 100 return textView.getSelectionStart() != textView.getSelectionEnd(); 101 } 102 103 boolean isScrollLocked() { 104 return locked; 105 } 106 107 114 public final void ensureCaretPosition() { 115 if (locked) { 116 if (!enqueued) { 119 SwingUtilities.invokeLater(this); 120 enqueued = true; 121 } 122 } 123 } 124 125 126 private boolean enqueued = false; 127 131 public void run() { 132 enqueued = false; 133 getVerticalScrollBar().setValue(getVerticalScrollBar().getModel().getMaximum()); 134 getHorizontalScrollBar().setValue(getHorizontalScrollBar().getModel().getMinimum()); 135 } 136 137 public int getSelectionStart() { 138 return textView.getSelectionStart(); 139 } 140 141 public int getSelectionEnd() { 142 return textView.getSelectionEnd(); 143 } 144 145 public void setSelection (int start, int end) { 146 int rstart = Math.min (start, end); 147 int rend = Math.max (start, end); 148 if (rstart == rend) { 149 getCaret().setDot(rstart); 150 } else { 151 textView.setSelectionStart(rstart); 152 textView.setSelectionEnd(rend); 153 } 154 } 155 156 public void selectAll() { 157 unlockScroll(); 158 getCaret().setVisible(true); 159 textView.setSelectionStart(0); 160 textView.setSelectionEnd(getLength()); 161 } 162 163 public boolean isAllSelected() { 164 return textView.getSelectionStart() == 0 && textView.getSelectionEnd() == getLength(); 165 } 166 167 protected void init() { 168 setViewportView(textView); 169 textView.setEditable(false); 170 171 textView.addMouseListener(this); 172 textView.addMouseWheelListener(this); 173 textView.addMouseMotionListener(this); 174 textView.addKeyListener(this); 175 textView.setCaret (new OCaret()); 176 177 getCaret().setVisible(true); 178 getCaret().setBlinkRate(0); 179 getCaret().setSelectionVisible(true); 180 181 getVerticalScrollBar().getModel().addChangeListener(this); 182 getVerticalScrollBar().addMouseMotionListener(this); 183 184 getViewport().addMouseListener(this); 185 getVerticalScrollBar().addMouseListener(this); 186 setHorizontalScrollBarPolicy(HORIZONTAL_SCROLLBAR_AS_NEEDED); 187 setVerticalScrollBarPolicy(VERTICAL_SCROLLBAR_ALWAYS); 188 addMouseListener(this); 189 190 getCaret().addChangeListener(this); 191 Integer i = (Integer ) UIManager.get("customFontSize"); int size; 193 if (i != null) { 194 size = i.intValue(); 195 } else { 196 Font f = (Font) UIManager.get("controlFont"); 197 size = f != null ? f.getSize() : 11; 198 } 199 textView.setFont (new Font ("Monospaced", Font.PLAIN, size)); setBorder (BorderFactory.createEmptyBorder()); 201 setViewportBorder (BorderFactory.createEmptyBorder()); 202 203 Color c = UIManager.getColor("nb.output.selectionBackground"); 204 if (c != null) { 205 textView.setSelectionColor(c); 206 } 207 } 208 209 public final Document getDocument() { 210 return textView.getDocument(); 211 } 212 213 216 public final JTextComponent getTextView() { 217 return textView; 218 } 219 220 public final void copy() { 221 if (getCaret().getDot() != getCaret().getMark()) { 222 textView.copy(); 223 } else { 224 Toolkit.getDefaultToolkit().beep(); 225 } 226 } 227 228 protected void setDocument (Document doc) { 229 if (hasSelection()) { 230 hasSelectionChanged(false); 231 } 232 hadSelection = false; 233 lastCaretLine = 0; 234 lastLength = -1; 235 Document old = textView.getDocument(); 236 old.removeDocumentListener(this); 237 if (doc != null) { 238 textView.setDocument(doc); 239 doc.addDocumentListener(this); 240 lockScroll(); 241 recentlyReset = true; 242 pendingCaretLine = -1; 243 } else { 244 textView.setDocument (new PlainDocument()); 245 textView.setEditorKit(new DefaultEditorKit()); 246 } 247 } 248 249 protected void setEditorKit(EditorKit kit) { 250 Document doc = textView.getDocument(); 251 252 textView.setEditorKit(kit); 253 textView.setDocument(doc); 254 updateKeyBindings(); 255 getCaret().setVisible(true); 256 getCaret().setBlinkRate(0); 257 } 258 259 263 protected final void updateKeyBindings() { 264 Keymap keymap = textView.getKeymap(); 265 keymap.removeKeyStrokeBinding(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0)); 266 } 267 268 protected EditorKit getEditorKit() { 269 return textView.getEditorKit(); 270 } 271 272 public final int getLineCount() { 273 return textView.getDocument().getDefaultRootElement().getElementCount(); 274 } 275 276 private int lastLength = -1; 277 public final int getLength() { 278 if (lastLength == -1) { 279 lastLength = textView.getDocument().getLength(); 280 } 281 return lastLength; 282 } 283 284 289 private int pendingCaretLine = -1; 290 private boolean pendingCaretSelect = false; 291 private boolean inSendCaretToLine = false; 292 293 public final boolean sendCaretToLine(int idx, boolean select) { 294 int count = getLineCount(); 295 if (count - idx < 3) { 296 pendingCaretLine = idx; 297 pendingCaretSelect = select; 298 return false; 299 } else { 300 inSendCaretToLine = true; 301 pendingCaretLine = -1; 302 unlockScroll(); 303 getCaret().setVisible(true); 304 getCaret().setSelectionVisible(true); 305 Element el = textView.getDocument().getDefaultRootElement().getElement(Math.min(idx, getLineCount() - 1)); 306 int position = el.getStartOffset(); 307 if (select) { 308 getCaret().setDot (el.getEndOffset()-1); 309 getCaret().moveDot (position); 310 getCaret().setSelectionVisible(true); 311 textView.repaint(); 312 } else { 313 getCaret().setDot(position); 314 } 315 if (idx + 3 < getLineCount()) { 316 try { 317 Rectangle r = textView.modelToView(textView.getDocument().getDefaultRootElement().getElement(idx + 3).getStartOffset()); 318 if (r != null) { textView.scrollRectToVisible(r); 320 } 321 } catch (BadLocationException ble) { 322 Exceptions.printStackTrace(ble); 323 } 324 } 325 inSendCaretToLine = false; 326 return true; 327 } 328 } 329 330 331 public final void lockScroll() { 332 if (!locked) { 333 locked = true; 334 } 335 } 336 337 public final void unlockScroll() { 338 if (locked) { 339 locked = false; 340 } 341 } 342 343 protected abstract void caretEnteredLine (int line); 344 345 protected abstract void lineClicked (int line, Point p); 346 347 protected abstract void postPopupMenu (Point p, Component src); 348 349 public final int getCaretLine() { 350 int result = -1; 351 int charPos = getCaret().getDot(); 352 if (charPos > 0) { 353 result = textView.getDocument().getDefaultRootElement().getElementIndex(charPos); 354 } 355 return result; 356 } 357 358 public final int getCaretPos() { 359 return getCaret().getDot(); 360 } 361 362 public final void paint (Graphics g) { 363 if (fontHeight == -1) { 364 fontHeight = g.getFontMetrics(textView.getFont()).getHeight(); 365 fontWidth = g.getFontMetrics(textView.getFont()).charWidth('m'); } 367 super.paint(g); 368 } 369 370 372 public void stateChanged(ChangeEvent e) { 373 if (e.getSource() instanceof JViewport) { 374 if (locked) { 375 ensureCaretPosition(); 376 } 377 } else if (e.getSource() == getVerticalScrollBar().getModel()) { 378 if (!locked) { BoundedRangeModel mdl = getVerticalScrollBar().getModel(); 380 if (mdl.getValue() + mdl.getExtent() == mdl.getMaximum()) { 381 lockScroll(); 382 } 383 } 384 } else { 385 if (!locked) { 386 maybeSendCaretEnteredLine(); 387 } 388 boolean hasSelection = textView.getSelectionStart() != textView.getSelectionEnd(); 389 if (hasSelection != hadSelection) { 390 hadSelection = hasSelection; 391 hasSelectionChanged (hasSelection); 392 } 393 } 394 } 395 396 private boolean caretLineChanged() { 397 int line = getCaretLine(); 398 boolean result = line != lastCaretLine; 399 lastCaretLine = line; 400 return result; 401 } 402 403 private void maybeSendCaretEnteredLine() { 404 if (EventQueue.getCurrentEvent() instanceof MouseEvent) { 405 return; 409 } 410 if ((!locked && caretLineChanged()) && !inSendCaretToLine) { 415 int line = getCaretLine(); 416 boolean sel = textView.getSelectionStart() != textView.getSelectionEnd(); 417 if (line != -1 && !sel) { 418 caretEnteredLine(getCaretLine()); 419 } 420 if (sel != hadSelection) { 421 hadSelection = sel; 422 hasSelectionChanged (sel); 423 } 424 } 425 } 426 427 428 private void hasSelectionChanged(boolean sel) { 429 ((AbstractOutputTab) getParent()).hasSelectionChanged(sel); 430 } 431 432 public final void changedUpdate(DocumentEvent e) { 433 e.getLength(); 435 documentChanged(); 436 } 437 438 public final void insertUpdate(DocumentEvent e) { 439 e.getLength(); 441 documentChanged(); 442 } 443 444 public final void removeUpdate(DocumentEvent e) { 445 e.getLength(); 447 documentChanged(); 448 } 449 450 public void mouseClicked(MouseEvent e) { 451 } 452 453 public void mouseEntered(MouseEvent e) { 454 } 455 456 public void mouseExited(MouseEvent e) { 457 setMouseLine (-1); 458 } 459 460 private int mouseLine = -1; 461 public void setMouseLine (int line, Point p) { 462 if (mouseLine != line) { 463 mouseLine = line; 464 } 465 } 466 467 public final void setMouseLine (int line) { 468 setMouseLine (line, null); 469 } 470 471 472 public void mouseMoved(MouseEvent e) { 473 Point p = e.getPoint(); 474 int pos = textView.viewToModel(p); 475 if (pos < getLength()) { 476 int line = getDocument().getDefaultRootElement().getElementIndex(pos); 477 int lineStart = getDocument().getDefaultRootElement().getElement(line).getStartOffset(); 478 int lineLength = getDocument().getDefaultRootElement().getElement(line).getEndOffset() - 479 lineStart; 480 481 try { 482 Rectangle r = textView.modelToView(lineStart + lineLength -1); 483 int maxX = r.x + r.width; 484 boolean inLine = p.x <= maxX; 485 if (isWrapped()) { 486 Rectangle ra = textView.modelToView(lineStart); 487 if (ra.y <= r.y) { 488 if (p.y < r.y) { 489 inLine = true; 490 } 491 } 492 } 493 494 if (inLine) { 495 setMouseLine (line, p); 496 } else { 497 setMouseLine(-1); 498 } 499 } catch (BadLocationException ble) { 500 setMouseLine(-1); 501 } 502 } 503 } 504 505 public void mouseDragged(MouseEvent e) { 506 if (e.getSource() == getVerticalScrollBar()) { 507 int y = e.getY(); 508 if (y > getVerticalScrollBar().getHeight()) { 509 lockScroll(); 510 } 511 } 512 } 513 514 public void mousePressed(MouseEvent e) { 515 if (locked && !e.isPopupTrigger()) { 516 Element el = getDocument().getDefaultRootElement().getElement(getLineCount()-1); 517 getCaret().setDot(el.getStartOffset()); 518 unlockScroll(); 519 if (e.getSource() == textView) { 522 getCaret().setDot (textView.viewToModel(e.getPoint())); 523 } 524 } 525 if (e.isPopupTrigger()) { 526 Point p = SwingUtilities.convertPoint((Component) e.getSource(), 530 e.getPoint(), this); 531 532 postPopupMenu (p, this); 533 } 534 } 535 536 public final void mouseReleased(MouseEvent e) { 537 if (e.getSource() == textView && SwingUtilities.isLeftMouseButton(e)) { 538 int pos = textView.viewToModel(e.getPoint()); 539 if (pos != -1) { 540 int line = textView.getDocument().getDefaultRootElement().getElementIndex(pos); 541 if (line >= 0) { 542 lineClicked(line, e.getPoint()); 543 e.consume(); } 545 } 546 } 547 if (e.isPopupTrigger()) { 548 Point p = SwingUtilities.convertPoint((Component) e.getSource(), 549 e.getPoint(), this); 553 554 postPopupMenu (p, this); 555 } 556 } 557 558 public void keyPressed(KeyEvent keyEvent) { 559 if (keyEvent.getKeyCode() == KeyEvent.VK_END) { 560 lockScroll(); 561 } else { 562 unlockScroll(); 563 } 564 } 565 566 public void keyReleased(KeyEvent keyEvent) { 567 } 568 569 public void keyTyped(KeyEvent keyEvent) { 570 } 571 572 public final void mouseWheelMoved(MouseWheelEvent e) { 573 BoundedRangeModel sbmodel = getVerticalScrollBar().getModel(); 574 int max = sbmodel.getMaximum(); 575 int range = sbmodel.getExtent(); 576 577 int currPosition = sbmodel.getValue(); 578 if (e.getSource() == textView) { 579 int newPosition = Math.max (0, Math.min (sbmodel.getMaximum(), 580 currPosition + (e.getUnitsToScroll() * textView.getFontMetrics(textView.getFont()).getHeight()))); 581 sbmodel.setValue (newPosition); 583 if (newPosition + range >= max) { 584 lockScroll(); 585 return; 586 } 587 } 588 unlockScroll(); 589 } 590 591 Caret getCaret() { 592 return textView.getCaret(); 593 } 594 595 private class OCaret extends DefaultCaret { 596 public void setSelectionVisible(boolean val) { 597 super.setSelectionVisible(true); 598 super.setBlinkRate(0); 599 } 600 public boolean isSelectionVisible() { 601 return true; 602 } 603 public void setBlinkRate(int rate) { 604 super.setBlinkRate(0); 605 } 606 607 public boolean isVisible() { return true; } 608 609 public void paint(Graphics g) { 610 JTextComponent component = textView; 611 if(isVisible() && y >= 0) { 612 try { 613 TextUI mapper = component.getUI(); 614 Rectangle r = mapper.modelToView(component, getDot(), Position.Bias.Forward); 615 616 if ((r == null) || ((r.width == 0) && (r.height == 0))) { 617 return; 618 } 619 if (width > 0 && height > 0 && 620 !this._contains(r.x, r.y, r.width, r.height)) { 621 Rectangle clip = g.getClipBounds(); 624 625 if (clip != null && !clip.contains(this)) { 626 repaint(); 629 } 630 632 damage(r); 636 } 637 g.setColor(component.getCaretColor()); 638 g.drawLine(r.x, r.y, r.x, r.y + r.height - 1); 639 640 } catch (BadLocationException e) { 641 } 644 } 645 } 646 647 private boolean _contains(int X, int Y, int W, int H) { 648 int w = this.width; 649 int h = this.height; 650 if ((w | h | W | H) < 0) { 651 return false; 653 } 654 int x = this.x; 656 int y = this.y; 657 if (X < x || Y < y) { 658 return false; 659 } 660 if (W > 0) { 661 w += x; 662 W += X; 663 if (W <= X) { 664 if (w >= x || W > w) { 669 return false; 670 } 671 } else { 672 if (w >= x && W > w) { 676 return true; 678 } 679 } 680 } 681 else if ((x + w) < X) { 682 return false; 683 } 684 if (H > 0) { 685 h += y; 686 H += Y; 687 if (H <= Y) { 688 if (h >= y || H > h) return false; 689 } else { 690 if (h >= y && H > h) return false; 691 } 692 } 693 else if ((y + h) < Y) { 694 return false; 695 } 696 return true; 697 } 698 699 public void mouseReleased(MouseEvent e) { 700 if( !e.isConsumed() ) 701 super.mouseReleased(e); 702 } 703 } 704 } 705 | Popular Tags |