KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > antlr > works > ate > ATEPanel


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 JavaDoc;
19 import javax.swing.event.CaretListener JavaDoc;
20 import javax.swing.event.DocumentEvent JavaDoc;
21 import javax.swing.event.DocumentListener JavaDoc;
22 import javax.swing.text.*;
23 import java.awt.*;
24 import java.awt.event.MouseAdapter JavaDoc;
25 import java.awt.event.MouseEvent JavaDoc;
26 import java.awt.event.MouseMotionAdapter JavaDoc;
27 import java.awt.print.PageFormat JavaDoc;
28 import java.awt.print.Printable JavaDoc;
29 import java.awt.print.PrinterException JavaDoc;
30 import java.awt.print.PrinterJob JavaDoc;
31 import java.util.List JavaDoc;
32 /*
33
34 [The "BSD licence"]
35 Copyright (c) 2005 Jean Bovet
36 All rights reserved.
37
38 Redistribution and use in source and binary forms, with or without
39 modification, are permitted provided that the following conditions
40 are met:
41
42 1. Redistributions of source code must retain the above copyright
43 notice, this list of conditions and the following disclaimer.
44 2. Redistributions in binary form must reproduce the above copyright
45 notice, this list of conditions and the following disclaimer in the
46 documentation and/or other materials provided with the distribution.
47 3. The name of the author may not be used to endorse or promote products
48 derived from this software without specific prior written permission.
49
50 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
51 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
52 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
53 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
54 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
55 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
56 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
57 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
58 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
59 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
60
61 */

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 JavaDoc 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                     // Will move the caret after the scrolling
203
// has completed (see smoothScrollingDidComplete())
204
caretPosition = position;
205                     smoothScrolling.scrollTo(r);
206                 } else
207                     textPane.scrollRectToVisible(r);
208             }
209         } catch (BadLocationException ble) {
210             // ignore
211
}
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         // Set by default the end of line property in order to always use the Unix style
255
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         // Method called only when a change occurred in the document
281
// which needs an immediate effect (in this case, the gutter
282
// has to be repainted)
283
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 JavaDoc getSelectedText() {
296         return textPane.getSelectedText();
297     }
298
299     public List JavaDoc<ATEToken> getTokens() {
300         return engine==null?null:engine.getTokens();
301     }
302
303     public List JavaDoc<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 JavaDoc<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 JavaDoc<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     /** This method is used when loading the text (mostly for the first time):
363      * it loads the text and parse it in the current thread in order to speed-up
364      * the display time (see ATEColorizing.processColorize(true)).
365      */

366
367     public void loadText(String JavaDoc 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 JavaDoc e) {
382             e.printStackTrace();
383         } finally {
384             setEnableRecordChange(true);
385         }
386     }
387
388     public void setText(String JavaDoc 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             // ignore
396
}
397         getTextPaneUndo().endUndoGroup();
398     }
399
400     public void insertText(int index, String JavaDoc 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 JavaDoc replace) {
409         replaceText(getSelectionStart(), getSelectionEnd(), replace);
410     }
411
412     public void replaceText(int start, int end, String JavaDoc 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 JavaDoc normalizeText(String JavaDoc 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 JavaDoc {
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         // Set by default the end of line property in order to always use the Unix style
463
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
472
gutter = new ATEGutter(this);
473
474         // Key bindings
475
keyBindings = new ATEKeyBindings(getTextPane());
476
477         // Scroll pane
478
JScrollPane textScrollPane = new JScrollPane(textPane);
479         textScrollPane.setWheelScrollingEnabled(true);
480         textScrollPane.setRowHeaderView(gutter);
481
482         // Analysis column
483
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 JavaDoc 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 JavaDoc {
558
559         public void caretUpdate(CaretEvent JavaDoc e) {
560             if(delegate != null)
561                 delegate.ateCaretUpdate(e.getDot());
562
563             // Each time the cursor moves, update the visible part of the text pane
564
// to redraw the highlighting
565
if(textPane.highlightCursorLine)
566                 textPane.repaint();
567         }
568     }
569
570     protected class TextPaneListener implements DocumentListener JavaDoc {
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 JavaDoc e) {
600             changeUpdate(e.getOffset(), e.getLength(), true);
601         }
602
603         public void removeUpdate(DocumentEvent JavaDoc e) {
604             changeUpdate(e.getOffset(), -e.getLength(), false);
605         }
606
607         public void changedUpdate(DocumentEvent JavaDoc e) {
608         }
609
610     }
611
612     protected class TextPaneMouseAdapter extends MouseAdapter JavaDoc {
613         public void mousePressed(MouseEvent JavaDoc e) {
614             // Update the cursor highligthing
615
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 JavaDoc e) {
625             checkForPopupTrigger(e);
626         }
627
628         public void checkForPopupTrigger(MouseEvent JavaDoc 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 JavaDoc e) {
642             if(delegate != null)
643                 delegate.ateMouseExited();
644         }
645     }
646
647     protected class TextPaneMouseMotionAdapter extends MouseMotionAdapter JavaDoc {
648         public void mouseMoved(MouseEvent JavaDoc e) {
649             if(delegate != null)
650                 delegate.ateMouseMoved(e.getPoint());
651         }
652     }
653
654     public class ATEPrintUtility implements Printable JavaDoc {
655
656         public ATEPrintUtility() {
657         }
658
659         public void print() throws PrinterException JavaDoc {
660             PrinterJob JavaDoc printJob = PrinterJob.getPrinterJob();
661             printJob.setPrintable(this);
662             if (printJob.printDialog()) {
663                 printJob.print();
664             }
665         }
666
667         public int print(Graphics g, PageFormat JavaDoc 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                 // Offset to the beginning of the printable region
687
g2.translate(pf.getImageableX(), pf.getImageableY());
688
689                 // Offset to the beginning of the page to render
690
double offsety = pageIndex * (int)numberOfLinesPerPage * lineHeight;
691                 g2.translate(0f, -offsety);
692
693                 // Set the clip to draw only a integer number of lines (and not a fraction of it)
694
g2.setClip(null);
695                 g2.clipRect(0, (int)(offsety), (int)Math.floor(pageWidth), (int)Math.floor((int)numberOfLinesPerPage*lineHeight));
696
697                 // Apply the scaling to the graphics
698
g2.scale(scale, scale);
699
700                 textPane.printPaint(g2);
701
702                 // debug frame
703
//g2.setColor(Color.red);
704
//g2.drawRect(0, (int)(offsety/scale), (int)Math.floor(pageWidth/scale), (int)Math.floor((int)numberOfLinesPerPage*lineHeight/scale));
705

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