1 package org.antlr.works.ate; 2 3 import org.antlr.works.ate.analysis.ATEAnalysisColumn; 4 import org.antlr.works.ate.analysis.ATEAnalysisManager; 5 import org.antlr.works.ate.breakpoint.ATEBreakpointManager; 6 import org.antlr.works.ate.folding.ATEFoldingManager; 7 import org.antlr.works.ate.swing.ATEAutoIndentation; 8 import org.antlr.works.ate.swing.ATEKeyBindings; 9 import org.antlr.works.ate.syntax.generic.ATESyntaxEngine; 10 import org.antlr.works.ate.syntax.generic.ATESyntaxEngineDelegate; 11 import org.antlr.works.ate.syntax.misc.ATELine; 12 import org.antlr.works.ate.syntax.misc.ATEToken; 13 import org.antlr.xjlib.appkit.frame.XJFrameInterface; 14 import org.antlr.xjlib.appkit.undo.XJUndo; 15 import org.antlr.xjlib.appkit.utils.XJSmoothScrolling; 16 17 import javax.swing.*; 18 import javax.swing.event.CaretEvent ; 19 import javax.swing.event.CaretListener ; 20 import javax.swing.event.DocumentEvent ; 21 import javax.swing.event.DocumentListener ; 22 import javax.swing.text.*; 23 import java.awt.*; 24 import java.awt.event.MouseAdapter ; 25 import java.awt.event.MouseEvent ; 26 import java.awt.event.MouseMotionAdapter ; 27 import java.awt.print.PageFormat ; 28 import java.awt.print.Printable ; 29 import java.awt.print.PrinterException ; 30 import java.awt.print.PrinterJob ; 31 import java.util.List ; 32 62 63 public class ATEPanel extends JPanel implements XJSmoothScrolling.ScrollingDelegate, ATESyntaxEngineDelegate { 64 65 protected XJFrameInterface parentFrame; 66 protected XJSmoothScrolling smoothScrolling; 67 68 protected ATEPanelDelegate delegate; 69 protected ATETextPane textPane; 70 protected ATEKeyBindings keyBindings; 71 protected ATEGutter gutter; 72 protected ATEAnalysisColumn analysisColumn; 73 74 protected ATEBreakpointManager breakpointManager; 75 protected ATEFoldingManager foldingManager; 76 protected ATEUnderlyingManager underlyingManager; 77 protected ATEAnalysisManager analysisManager; 78 79 protected ATESyntaxEngine engine; 80 protected ATEAutoIndentation autoIndent; 81 82 protected TextPaneListener textPaneListener; 83 84 protected boolean syntaxColoring = false; 85 protected int caretPosition; 86 87 protected static final String unixEndOfLine = "\n"; 88 protected static int ANALYSIS_COLUMN_WIDTH = 18; 89 90 public ATEPanel(XJFrameInterface parentFrame) { 91 this(parentFrame, null); 92 } 93 94 public ATEPanel(XJFrameInterface parentFrame, StyledEditorKit editorKit) { 95 super(new BorderLayout()); 96 this.parentFrame = parentFrame; 97 autoIndent = new ATEAutoIndentation(this); 98 createTextPane(editorKit); 99 } 100 101 public XJFrameInterface getParentFrame() { 102 return parentFrame; 103 } 104 105 public void setParserEngine(ATESyntaxEngine engine) { 106 this.engine = engine; 107 this.engine.setDelegate(this); 108 this.engine.refreshColoring(); 109 } 110 111 public ATESyntaxEngine getParserEngine() { 112 return engine; 113 } 114 115 public void setDelegate(ATEPanelDelegate delegate) { 116 this.delegate = delegate; 117 } 118 119 public void setBreakpointManager(ATEBreakpointManager manager) { 120 this.breakpointManager = manager; 121 } 122 123 public void setFoldingManager(ATEFoldingManager manager) { 124 this.foldingManager = manager; 125 } 126 127 public void setUnderlyingManager(ATEUnderlyingManager manager) { 128 this.underlyingManager = manager; 129 } 130 131 public void setAnalysisManager(ATEAnalysisManager manager) { 132 this.analysisManager = manager; 133 } 134 135 public ATEAnalysisManager getAnalysisManager() { 136 return analysisManager; 137 } 138 139 public void setEditable(boolean flag) { 140 textPane.setEditable(flag); 141 textPane.setWritable(flag); 142 } 143 144 public void setAutoIndent(boolean flag) { 145 autoIndent.setEnabled(flag); 146 } 147 148 public boolean autoIndent() { 149 return autoIndent.enabled(); 150 } 151 152 public void setCaretPosition(int position) { 153 setCaretPosition(position, true, false); 154 } 155 156 public void setCaretPosition(int position, boolean adjustScroll, boolean animate) { 157 if(adjustScroll) 158 scrollCenterToPosition(position, animate); 159 if(!animate) 160 textPane.setCaretPosition(position); 161 } 162 163 public int getCaretPosition() { 164 return textPane.getCaretPosition(); 165 } 166 167 public void setHighlightCursorLine(boolean flag) { 168 textPane.setHighlightCursorLine(flag); 169 } 170 171 public void setUnderlying(boolean flag) { 172 underlyingManager.setUnderlying(flag); 173 } 174 175 public boolean isUnderlying() { 176 return underlyingManager.underlying; 177 } 178 179 public void setFoldingEnabled(boolean flag) { 180 gutter.setFoldingEnabled(flag); 181 } 182 183 public void setLineNumberEnabled(boolean flag) { 184 gutter.setLineNumberEnabled(flag); 185 } 186 187 public void setEnableRecordChange(boolean flag) { 188 if(flag) 189 textPaneListener.enable(); 190 else 191 textPaneListener.disable(); 192 } 193 194 public void scrollCenterToPosition(int position, boolean animate) { 195 try { 196 Rectangle r = textPane.modelToView(position); 197 if(r != null) { 198 Rectangle vis = getVisibleRect(); 199 r.y -= (vis.height / 2); 200 r.height = vis.height; 201 if(animate) { 202 caretPosition = position; 205 smoothScrolling.scrollTo(r); 206 } else 207 textPane.scrollRectToVisible(r); 208 } 209 } catch (BadLocationException ble) { 210 } 212 } 213 214 public void smoothScrollingDidComplete() { 215 textPane.setCaretPosition(caretPosition); 216 } 217 218 public void setAnalysisColumnVisible(boolean visible) { 219 analysisColumn.setVisible(visible); 220 if(visible) 221 analysisColumn.setPreferredSize(new Dimension(ANALYSIS_COLUMN_WIDTH, 0)); 222 else 223 analysisColumn.setPreferredSize(new Dimension(0, 0)); 224 } 225 226 public boolean isAnalysisColumnVisible() { 227 return analysisColumn.isVisible(); 228 } 229 230 public void toggleAnalysis() { 231 setAnalysisColumnVisible(!isAnalysisColumnVisible()); 232 } 233 234 public void setSyntaxColoring(boolean flag) { 235 this.syntaxColoring = flag; 236 textPane.repaint(); 237 } 238 239 public boolean isSyntaxColoring() { 240 return syntaxColoring; 241 } 242 243 public ATEKeyBindings getKeyBindings() { 244 return keyBindings; 245 } 246 247 public void toggleSyntaxColoring() { 248 setSyntaxColoring(!isSyntaxColoring()); 249 } 250 251 public void setEditorKit(StyledEditorKit editorKit) { 252 textPane.setEditorKit(editorKit); 253 textPane.getDocument().addDocumentListener(textPaneListener = new TextPaneListener()); 254 textPane.getDocument().putProperty(DefaultEditorKit.EndOfLineStringProperty, unixEndOfLine); 256 } 257 258 public void damage() { 259 if(underlyingManager != null) { 260 underlyingManager.reset(); 261 } 262 263 if(gutter != null) { 264 gutter.updateSize(); 265 gutter.revalidate(); 266 gutter.markDirty(); 267 } 268 } 269 270 public void refresh() { 271 damage(); 272 273 if(engine != null) 274 engine.refreshColoring(); 275 276 repaint(); 277 } 278 279 public void changeOccurred() { 280 gutter.markDirty(); 284 parse(); 285 } 286 287 public int getSelectionStart() { 288 return textPane.getSelectionStart(); 289 } 290 291 public int getSelectionEnd() { 292 return textPane.getSelectionEnd(); 293 } 294 295 public String getSelectedText() { 296 return textPane.getSelectedText(); 297 } 298 299 public List <ATEToken> getTokens() { 300 return engine==null?null:engine.getTokens(); 301 } 302 303 public List <ATELine> getLines() { 304 return engine==null?null:engine.getLines(); 305 } 306 307 public int getCurrentLinePosition() { 308 return getLinePositionAtIndex(getCaretPosition()); 309 } 310 311 public int getLinePositionAtIndex(int index) { 312 return getLineIndexAtTextPosition(index) + 1; 313 } 314 315 public int getCurrentColumnPosition() { 316 return getColumnPositionAtIndex(getCaretPosition()); 317 } 318 319 public int getColumnPositionAtIndex(int index) { 320 int lineIndex = getLineIndexAtTextPosition(index); 321 Point linePosition = getLineTextPositionsAtLineIndex(lineIndex); 322 if(linePosition == null) 323 return 1; 324 else 325 return getCaretPosition() - linePosition.x + 1; 326 } 327 328 public int getLineIndexAtTextPosition(int pos) { 329 List <ATELine> lines = getLines(); 330 if(lines == null) 331 return -1; 332 333 for(int i=0; i<lines.size(); i++) { 334 ATELine line = lines.get(i); 335 if(line.position > pos) { 336 return i-1; 337 } 338 } 339 return lines.size()-1; 340 } 341 342 public Point getLineTextPositionsAtTextPosition(int pos) { 343 return getLineTextPositionsAtLineIndex(getLineIndexAtTextPosition(pos)); 344 } 345 346 public Point getLineTextPositionsAtLineIndex(int lineIndex) { 347 List <ATELine> lines = getLines(); 348 if(lineIndex == -1 || lines == null) 349 return null; 350 351 ATELine startLine = lines.get(lineIndex); 352 int start = startLine.position; 353 if(lineIndex+1 >= lines.size()) { 354 return new Point(start, getTextPane().getDocument().getLength()-1); 355 } else { 356 ATELine endLine = lines.get(lineIndex+1); 357 int end = endLine.position; 358 return new Point(start, end-1); 359 } 360 } 361 362 366 367 public void loadText(String text) { 368 setEnableRecordChange(false); 369 try { 370 ateEngineWillParse(); 371 372 textPane.setText(normalizeText(text)); 373 if(engine != null) 374 engine.processSyntax(); 375 376 textPane.setCaretPosition(0); 377 textPane.moveCaretPosition(0); 378 textPane.getCaret().setSelectionVisible(true); 379 380 ateEngineDidParse(); 381 } catch(Exception e) { 382 e.printStackTrace(); 383 } finally { 384 setEnableRecordChange(true); 385 } 386 } 387 388 public void setText(String text) { 389 Document doc = textPane.getDocument(); 390 getTextPaneUndo().beginUndoGroup("setText"); 391 try { 392 doc.remove(0, doc.getLength()); 393 doc.insertString(0, text, null); 394 } catch (BadLocationException e) { 395 } 397 getTextPaneUndo().endUndoGroup(); 398 } 399 400 public void insertText(int index, String text) { 401 try { 402 textPane.getDocument().insertString(index, normalizeText(text), null); 403 } catch (BadLocationException e) { 404 e.printStackTrace(); 405 } 406 } 407 408 public void replaceSelectedText(String replace) { 409 replaceText(getSelectionStart(), getSelectionEnd(), replace); 410 } 411 412 public void replaceText(int start, int end, String text) { 413 getTextPaneUndo().beginUndoGroup("replaceText"); 414 try { 415 textPane.getDocument().remove(start, end-start); 416 textPane.getDocument().insertString(start, normalizeText(text), null); 417 } catch (BadLocationException e) { 418 e.printStackTrace(); 419 } 420 getTextPaneUndo().endUndoGroup(); 421 } 422 423 public static String normalizeText(String text) { 424 return text.replaceAll(System.getProperty("line.separator"), "\n"); 425 } 426 427 public void selectTextRange(int start, int end) { 428 textPane.setCaretPosition(start); 429 textPane.moveCaretPosition(end); 430 textPane.getCaret().setSelectionVisible(true); 431 432 scrollCenterToPosition(start, false); 433 } 434 435 public void deselectTextRange() { 436 textPane.setCaretPosition(textPane.getCaretPosition()); 437 } 438 439 public void print() throws PrinterException { 440 new ATEPrintUtility().print(); 441 } 442 443 public void textPaneDidPaint(Graphics g) { 444 if(underlyingManager != null) 445 underlyingManager.paint(g); 446 } 447 448 public void textPaneInvokePopUp(Component component, int x, int y) { 449 if(delegate != null) 450 delegate.ateInvokePopUp(component, x, y); 451 } 452 453 protected void createTextPane(StyledEditorKit editorKit) { 454 textPane = new ATETextPane(this, editorKit); 455 textPane.setFocusable(true); 456 textPane.setBackground(Color.white); 457 textPane.setBorder(null); 458 459 textPane.setWordWrap(false); 460 461 textPane.getDocument().addDocumentListener(textPaneListener = new TextPaneListener()); 462 textPane.getDocument().putProperty(DefaultEditorKit.EndOfLineStringProperty, unixEndOfLine); 464 465 textPane.addCaretListener(new TextPaneCaretListener()); 466 textPane.addMouseListener(new TextPaneMouseAdapter()); 467 textPane.addMouseMotionListener(new TextPaneMouseMotionAdapter()); 468 469 smoothScrolling = new XJSmoothScrolling(textPane, this); 470 471 gutter = new ATEGutter(this); 473 474 keyBindings = new ATEKeyBindings(getTextPane()); 476 477 JScrollPane textScrollPane = new JScrollPane(textPane); 479 textScrollPane.setWheelScrollingEnabled(true); 480 textScrollPane.setRowHeaderView(gutter); 481 482 analysisColumn = new ATEAnalysisColumn(this); 484 analysisColumn.setMinimumSize(new Dimension(ANALYSIS_COLUMN_WIDTH, 0)); 485 analysisColumn.setMaximumSize(new Dimension(ANALYSIS_COLUMN_WIDTH, Integer.MAX_VALUE)); 486 analysisColumn.setPreferredSize(new Dimension(ANALYSIS_COLUMN_WIDTH, analysisColumn.getPreferredSize().height)); 487 488 Box box = Box.createHorizontalBox(); 489 box.add(textScrollPane); 490 box.add(analysisColumn); 491 492 add(box, BorderLayout.CENTER); 493 } 494 495 public ATETextPane getTextPane() { 496 return textPane; 497 } 498 499 public ATEGutter getGutter() { 500 return gutter; 501 } 502 503 public void parse() { 504 if(engine != null) 505 engine.process(); 506 } 507 508 public String getText() { 509 return getTextPane().getText(); 510 } 511 512 public void ateEngineWillParse() { 513 if(delegate != null) 514 delegate.ateParserWillParse(); 515 } 516 517 public void ateEngineDidParse() { 518 if(delegate != null) 519 delegate.ateParserDidParse(); 520 } 521 522 public void ateAutoIndent(int offset, int length) { 523 if(delegate != null) 524 delegate.ateAutoIndent(offset, length); 525 } 526 527 public void ateColoringWillColorize() { 528 setEnableRecordChange(false); 529 disableUndo(); 530 } 531 532 public void ateColoringDidColorize() { 533 setEnableRecordChange(true); 534 enableUndo(); 535 } 536 537 public XJUndo getTextPaneUndo() { 538 return parentFrame.getUndo(getTextPane()); 539 } 540 541 public void disableUndo() { 542 XJUndo undo = getTextPaneUndo(); 543 if(undo != null) 544 undo.disableUndo(); 545 } 546 547 public void enableUndo() { 548 XJUndo undo = getTextPaneUndo(); 549 if(undo != null) 550 undo.enableUndo(); 551 } 552 553 public int getTextIndexAtPosition(int x, int y) { 554 return getTextPane().viewToModel(new Point(x, y)); 555 } 556 557 protected class TextPaneCaretListener implements CaretListener { 558 559 public void caretUpdate(CaretEvent e) { 560 if(delegate != null) 561 delegate.ateCaretUpdate(e.getDot()); 562 563 if(textPane.highlightCursorLine) 566 textPane.repaint(); 567 } 568 } 569 570 protected class TextPaneListener implements DocumentListener { 571 572 protected int enable = 0; 573 574 public synchronized void enable() { 575 enable--; 576 } 577 578 public synchronized void disable() { 579 enable++; 580 } 581 582 public synchronized boolean isEnable() { 583 return enable == 0; 584 } 585 586 public void changeUpdate(int offset, int length, boolean insert) { 587 if(isEnable()) { 588 if(delegate != null) 589 delegate.ateChangeUpdate(offset, length, insert); 590 591 if(insert) { 592 autoIndent.indent(offset, length); 593 } 594 595 changeOccurred(); 596 } 597 } 598 599 public void insertUpdate(DocumentEvent e) { 600 changeUpdate(e.getOffset(), e.getLength(), true); 601 } 602 603 public void removeUpdate(DocumentEvent e) { 604 changeUpdate(e.getOffset(), -e.getLength(), false); 605 } 606 607 public void changedUpdate(DocumentEvent e) { 608 } 609 610 } 611 612 protected class TextPaneMouseAdapter extends MouseAdapter { 613 public void mousePressed(MouseEvent e) { 614 if(textPane.highlightCursorLine) 616 textPane.repaint(); 617 618 checkForPopupTrigger(e); 619 620 if(delegate != null) 621 delegate.ateMousePressed(e.getPoint()); 622 } 623 624 public void mouseReleased(MouseEvent e) { 625 checkForPopupTrigger(e); 626 } 627 628 public void checkForPopupTrigger(MouseEvent e) { 629 if(e.isPopupTrigger()) { 630 int index = textPane.viewToModel(e.getPoint()); 631 if(textPane.getSelectionStart() != textPane.getSelectionEnd()) { 632 if(index < textPane.getSelectionStart() || index > textPane.getSelectionEnd()) 633 setCaretPosition(index, false, false); 634 } else if(index != getCaretPosition()) 635 setCaretPosition(index, false, false); 636 637 textPaneInvokePopUp(e.getComponent(), e.getX(), e.getY()); 638 } 639 } 640 641 public void mouseExited(MouseEvent e) { 642 if(delegate != null) 643 delegate.ateMouseExited(); 644 } 645 } 646 647 protected class TextPaneMouseMotionAdapter extends MouseMotionAdapter { 648 public void mouseMoved(MouseEvent e) { 649 if(delegate != null) 650 delegate.ateMouseMoved(e.getPoint()); 651 } 652 } 653 654 public class ATEPrintUtility implements Printable { 655 656 public ATEPrintUtility() { 657 } 658 659 public void print() throws PrinterException { 660 PrinterJob printJob = PrinterJob.getPrinterJob(); 661 printJob.setPrintable(this); 662 if (printJob.printDialog()) { 663 printJob.print(); 664 } 665 } 666 667 public int print(Graphics g, PageFormat pf, int pageIndex) { 668 double pageWidth = pf.getImageableWidth(); 669 double pageHeight = pf.getImageableHeight(); 670 671 double preferredLineWidth = textPane.getUI().getRootView(textPane).getView(0).getPreferredSpan(View.X_AXIS); 672 double scale = pageWidth / preferredLineWidth; 673 double lineHeight = textPane.getFontMetrics(textPane.getFont()).getHeight() * scale; 674 675 double numberOfLinesPerPage = pageHeight / lineHeight; 676 double numberOfLines = textPane.getDocument().getDefaultRootElement().getElementCount(); 677 678 int totalNumPages = (int)Math.ceil(numberOfLines / numberOfLinesPerPage); 679 680 if (pageIndex >= totalNumPages) { 681 return NO_SUCH_PAGE; 682 } else { 683 Graphics2D g2 = (Graphics2D) g; 684 disableDoubleBuffering(textPane); 685 686 g2.translate(pf.getImageableX(), pf.getImageableY()); 688 689 double offsety = pageIndex * (int)numberOfLinesPerPage * lineHeight; 691 g2.translate(0f, -offsety); 692 693 g2.setClip(null); 695 g2.clipRect(0, (int)(offsety), (int)Math.floor(pageWidth), (int)Math.floor((int)numberOfLinesPerPage*lineHeight)); 696 697 g2.scale(scale, scale); 699 700 textPane.printPaint(g2); 701 702 706 enableDoubleBuffering(textPane); 707 return Printable.PAGE_EXISTS; 708 } 709 } 710 711 public void disableDoubleBuffering(Component c) { 712 RepaintManager currentManager = RepaintManager.currentManager(c); 713 currentManager.setDoubleBufferingEnabled(false); 714 } 715 716 public void enableDoubleBuffering(Component c) { 717 RepaintManager currentManager = RepaintManager.currentManager(c); 718 currentManager.setDoubleBufferingEnabled(true); 719 } 720 } 721 } 722 | Popular Tags |