Source Code Cross Referenced for JEditTextArea.java in  » XML-UI » XUI » net » xoetrope » builder » editor » syntaxhighlight » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » XML UI » XUI » net.xoetrope.builder.editor.syntaxhighlight 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        package net.xoetrope.builder.editor.syntaxhighlight;
0002:
0003:        /**
0004:         *  The syntax highlighting subpackage is a copy of the syntax highlighting
0005:         * component offered by syntax.jedit.org or via sourceforge under the MIT
0006:         * license. The site does not include the licens file but the MIT license is as
0007:         * follows:
0008:         *
0009:         * The MIT License
0010:         * Copyright (c) <year> <copyright holders>
0011:         *
0012:         * Permission is hereby granted, free of charge, to any person obtaining a copy
0013:         * of this software and associated documentation files (the "Software"), to deal
0014:         * in the Software without restriction, including without limitation the rights
0015:         * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
0016:         * copies of the Software, and to permit persons to whom the Software is
0017:         * furnished to do so, subject to the following conditions:
0018:         *
0019:         * The above copyright notice and this permission notice shall be included in
0020:         * all copies or substantial portions of the Software.
0021:         *
0022:         * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0023:         * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0024:         * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
0025:         * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
0026:         * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
0027:         * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
0028:         * SOFTWARE.s
0029:         */
0030:
0031:        /*
0032:         * JEditTextArea.java - jEdit's text component
0033:         * Copyright (C) 1999 Slava Pestov
0034:         *
0035:         * You may use and modify this package for any purpose. Redistribution is
0036:         * permitted, in both source and binary form, provided that this notice
0037:         * remains intact in all source distributions of this package.
0038:         */
0039:
0040:        import java.util.Enumeration;
0041:        import java.util.Vector;
0042:
0043:        import java.awt.AWTEvent;
0044:        import java.awt.Component;
0045:        import java.awt.Container;
0046:        import java.awt.Dimension;
0047:        import java.awt.Font;
0048:        import java.awt.FontMetrics;
0049:        import java.awt.Insets;
0050:        import java.awt.LayoutManager;
0051:        import java.awt.Toolkit;
0052:        import java.awt.datatransfer.Clipboard;
0053:        import java.awt.datatransfer.DataFlavor;
0054:        import java.awt.datatransfer.StringSelection;
0055:        import java.awt.event.ActionEvent;
0056:        import java.awt.event.ActionListener;
0057:        import java.awt.event.AdjustmentEvent;
0058:        import java.awt.event.AdjustmentListener;
0059:        import java.awt.event.ComponentAdapter;
0060:        import java.awt.event.ComponentEvent;
0061:        import java.awt.event.FocusEvent;
0062:        import java.awt.event.FocusListener;
0063:        import java.awt.event.InputEvent;
0064:        import java.awt.event.KeyEvent;
0065:        import java.awt.event.MouseAdapter;
0066:        import java.awt.event.MouseEvent;
0067:        import java.awt.event.MouseMotionListener;
0068:        import javax.swing.JComponent;
0069:        import javax.swing.JPopupMenu;
0070:        import javax.swing.JScrollBar;
0071:        import javax.swing.SwingUtilities;
0072:        import javax.swing.Timer;
0073:        import javax.swing.event.CaretEvent;
0074:        import javax.swing.event.CaretListener;
0075:        import javax.swing.event.DocumentEvent;
0076:        import javax.swing.event.DocumentListener;
0077:        import javax.swing.event.EventListenerList;
0078:        import javax.swing.text.BadLocationException;
0079:        import javax.swing.text.Element;
0080:        import javax.swing.text.Segment;
0081:        import javax.swing.text.Utilities;
0082:        import javax.swing.undo.AbstractUndoableEdit;
0083:        import javax.swing.undo.CannotRedoException;
0084:        import javax.swing.undo.CannotUndoException;
0085:        import javax.swing.undo.UndoableEdit;
0086:
0087:        /**
0088:         * jEdit's text area component. It is more suited for editing program
0089:         * source code than JEditorPane, because it drops the unnecessary features
0090:         * (images, variable-width lines, and so on) and adds a whole bunch of
0091:         * useful goodies such as:
0092:         * <ul>
0093:         * <li>More flexible key binding scheme
0094:         * <li>Supports macro recorders
0095:         * <li>Rectangular selection
0096:         * <li>Bracket highlighting
0097:         * <li>Syntax highlighting
0098:         * <li>Command repetition
0099:         * <li>Block caret can be enabled
0100:         * </ul>
0101:         * It is also faster and doesn't have as many problems. It can be used
0102:         * in other applications; the only other part of jEdit it depends on is
0103:         * the syntax package.<p>
0104:         *
0105:         * To use it in your app, treat it like any other component, for example:
0106:         * <pre>JEditTextArea ta = new JEditTextArea();
0107:         * ta.setTokenMarker(new JavaTokenMarker());
0108:         * ta.setText("public class Test {\n"
0109:         *     + "    public static void main(String[] args) {\n"
0110:         *     + "        System.out.println(\"Hello World\");\n"
0111:         *     + "    }\n"
0112:         *     + "}");</pre>
0113:         *
0114:         * @author Slava Pestov
0115:         * @version $Id: JEditTextArea.java,v 1.22 2005/01/05 17:20:48 luano Exp $
0116:         */
0117:        public class JEditTextArea extends JComponent {
0118:            /**
0119:             * Adding components with this name to the text area will place
0120:             * them left of the horizontal scroll bar. In jEdit, the status
0121:             * bar is added this way.
0122:             */
0123:            public static String LEFT_OF_SCROLLBAR = "los";
0124:
0125:            /**
0126:             * Creates a new JEditTextArea with the default settings.
0127:             */
0128:            public JEditTextArea() {
0129:                this (TextAreaDefaults.getDefaults());
0130:            }
0131:
0132:            /**
0133:             * Creates a new JEditTextArea with the specified settings.
0134:             * @param defaults The default settings
0135:             */
0136:            public JEditTextArea(TextAreaDefaults defaults) {
0137:                // Enable the necessary events
0138:                enableEvents(AWTEvent.KEY_EVENT_MASK);
0139:
0140:                // Initialize some misc. stuff
0141:                painter = new TextAreaPainter(this , defaults);
0142:                gutter = new Gutter(null, this );
0143:                gutter.setFont(painter.getFont());
0144:                documentHandler = new DocumentHandler();
0145:                listenerList = new EventListenerList();
0146:                caretEvent = new MutableCaretEvent();
0147:                lineSegment = new Segment();
0148:                bracketLine = bracketPosition = -1;
0149:                blink = true;
0150:
0151:                // Initialize the GUI
0152:                setLayout(new ScrollLayout());
0153:                add(LEFT, gutter);
0154:                add(CENTER, painter);
0155:                add(RIGHT, vertical = new JScrollBar(JScrollBar.VERTICAL));
0156:                add(BOTTOM, horizontal = new JScrollBar(JScrollBar.HORIZONTAL));
0157:
0158:                // Add some event listeners
0159:                vertical.addAdjustmentListener(new AdjustHandler());
0160:                horizontal.addAdjustmentListener(new AdjustHandler());
0161:                painter.addComponentListener(new ComponentHandler());
0162:                painter.addMouseListener(new MouseHandler());
0163:                painter.addMouseMotionListener(new DragHandler());
0164:                addFocusListener(new FocusHandler());
0165:
0166:                // Load the defaults
0167:                setInputHandler(defaults.inputHandler);
0168:                setDocument(defaults.document);
0169:                editable = defaults.editable;
0170:                caretVisible = defaults.caretVisible;
0171:                caretBlinks = defaults.caretBlinks;
0172:                electricScroll = defaults.electricScroll;
0173:
0174:                popup = defaults.popup;
0175:
0176:                // We don't seem to get the initial focus event?
0177:                focusedComponent = this ;
0178:            }
0179:
0180:            /**
0181:             * Returns if this component can be traversed by pressing
0182:             * the Tab key. This returns false.
0183:             */
0184:            public final boolean isManagingFocus() {
0185:                return true;
0186:            }
0187:
0188:            /**
0189:             * Returns the object responsible for painting this text area.
0190:             */
0191:            public final TextAreaPainter getPainter() {
0192:                return painter;
0193:            }
0194:
0195:            /**
0196:             * Returns the gutter to the left of the text area or null if the gutter
0197:             * is disabled
0198:             */
0199:            public final Gutter getGutter() {
0200:                return gutter;
0201:            }
0202:
0203:            /**
0204:             * Returns the input handler.
0205:             */
0206:            public final InputHandler getInputHandler() {
0207:                return inputHandler;
0208:            }
0209:
0210:            /**
0211:             * Sets the input handler.
0212:             * @param inputHandler The new input handler
0213:             */
0214:            public void setInputHandler(InputHandler inputHandler) {
0215:                this .inputHandler = inputHandler;
0216:            }
0217:
0218:            /**
0219:             * Returns true if the caret is blinking, false otherwise.
0220:             */
0221:            public final boolean isCaretBlinkEnabled() {
0222:                return caretBlinks;
0223:            }
0224:
0225:            /**
0226:             * Toggles caret blinking.
0227:             * @param caretBlinks True if the caret should blink, false otherwise
0228:             */
0229:            public void setCaretBlinkEnabled(boolean caretBlinks) {
0230:                this .caretBlinks = caretBlinks;
0231:                if (!caretBlinks)
0232:                    blink = false;
0233:
0234:                painter.invalidateSelectedLines();
0235:            }
0236:
0237:            /**
0238:             * Returns true if the caret is visible, false otherwise.
0239:             */
0240:            public final boolean isCaretVisible() {
0241:                return (!caretBlinks || blink) && caretVisible;
0242:            }
0243:
0244:            /**
0245:             * Sets if the caret should be visible.
0246:             * @param caretVisible True if the caret should be visible, false
0247:             * otherwise
0248:             */
0249:            public void setCaretVisible(boolean caretVisible) {
0250:                this .caretVisible = caretVisible;
0251:                blink = true;
0252:
0253:                painter.invalidateSelectedLines();
0254:            }
0255:
0256:            /**
0257:             * Blinks the caret.
0258:             */
0259:            public final void blinkCaret() {
0260:                if (caretBlinks) {
0261:                    blink = !blink;
0262:                    painter.invalidateSelectedLines();
0263:                } else
0264:                    blink = true;
0265:            }
0266:
0267:            /**
0268:             * Returns the number of lines from the top and button of the
0269:             * text area that are always visible.
0270:             */
0271:            public final int getElectricScroll() {
0272:                return electricScroll;
0273:            }
0274:
0275:            /**
0276:             * Sets the number of lines from the top and bottom of the text
0277:             * area that are always visible
0278:             * @param electricScroll The number of lines always visible from
0279:             * the top or bottom
0280:             */
0281:            public final void setElectricScroll(int electricScroll) {
0282:                this .electricScroll = electricScroll;
0283:            }
0284:
0285:            /**
0286:             * Updates the state of the scroll bars. This should be called
0287:             * if the number of lines in the document changes, or when the
0288:             * size of the text are changes.
0289:             */
0290:            public void updateScrollBars() {
0291:                if (vertical != null && visibleLines != 0) {
0292:                    vertical.setValues(firstLine, visibleLines, 0,
0293:                            getLineCount());
0294:                    vertical.setUnitIncrement(2);
0295:                    vertical.setBlockIncrement(visibleLines);
0296:                }
0297:
0298:                int width = painter.getWidth();
0299:                if (horizontal != null && width != 0) {
0300:                    horizontal
0301:                            .setValues(-horizontalOffset, width, 0, width * 5);
0302:                    horizontal.setUnitIncrement(painter.getFontMetrics()
0303:                            .charWidth('w'));
0304:                    horizontal.setBlockIncrement(width / 2);
0305:                }
0306:            }
0307:
0308:            /**
0309:             * Returns the line displayed at the text area's origin.
0310:             */
0311:            public final int getFirstLine() {
0312:                return firstLine;
0313:            }
0314:
0315:            /**
0316:             * Sets the line displayed at the text area's origin without
0317:             * updating the scroll bars.
0318:             */
0319:            public void setFirstLine(int firstLine) {
0320:                if (firstLine == this .firstLine)
0321:                    return;
0322:                int oldFirstLine = this .firstLine;
0323:                this .firstLine = firstLine;
0324:                if (firstLine != vertical.getValue())
0325:                    updateScrollBars();
0326:                painter.repaint();
0327:                gutter.repaint();
0328:            }
0329:
0330:            /**
0331:             * Returns the number of lines visible in this text area.
0332:             */
0333:            public final int getVisibleLines() {
0334:                return visibleLines;
0335:            }
0336:
0337:            /**
0338:             * Recalculates the number of visible lines. This should not
0339:             * be called directly.
0340:             */
0341:            public final void recalculateVisibleLines() {
0342:                if (painter == null)
0343:                    return;
0344:                int height = painter.getHeight();
0345:                int lineHeight = painter.getFontMetrics().getHeight();
0346:                int oldVisibleLines = visibleLines;
0347:                visibleLines = height / lineHeight;
0348:                updateScrollBars();
0349:            }
0350:
0351:            /**
0352:             * Returns the horizontal offset of drawn lines.
0353:             */
0354:            public final int getHorizontalOffset() {
0355:                return horizontalOffset;
0356:            }
0357:
0358:            /**
0359:             * Sets the horizontal offset of drawn lines. This can be used to
0360:             * implement horizontal scrolling.
0361:             * @param horizontalOffset offset The new horizontal offset
0362:             */
0363:            public void setHorizontalOffset(int horizontalOffset) {
0364:                if (horizontalOffset == this .horizontalOffset)
0365:                    return;
0366:                this .horizontalOffset = horizontalOffset;
0367:                if (horizontalOffset != horizontal.getValue())
0368:                    updateScrollBars();
0369:                painter.repaint();
0370:                gutter.repaint();
0371:            }
0372:
0373:            /**
0374:             * A fast way of changing both the first line and horizontal
0375:             * offset.
0376:             * @param firstLine The new first line
0377:             * @param horizontalOffset The new horizontal offset
0378:             * @return True if any of the values were changed, false otherwise
0379:             */
0380:            public boolean setOrigin(int firstLine, int horizontalOffset) {
0381:                boolean changed = false;
0382:                int oldFirstLine = this .firstLine;
0383:
0384:                if (horizontalOffset != this .horizontalOffset) {
0385:                    this .horizontalOffset = horizontalOffset;
0386:                    changed = true;
0387:                }
0388:
0389:                if (firstLine != this .firstLine) {
0390:                    this .firstLine = firstLine;
0391:                    changed = true;
0392:                }
0393:
0394:                if (changed) {
0395:                    updateScrollBars();
0396:                    painter.repaint();
0397:                    gutter.repaint();
0398:                }
0399:
0400:                return changed;
0401:            }
0402:
0403:            /**
0404:             * Ensures that the caret is visible by scrolling the text area if
0405:             * necessary.
0406:             * @return True if scrolling was actually performed, false if the
0407:             * caret was already visible
0408:             */
0409:            public boolean scrollToCaret() {
0410:                int line = getCaretLine();
0411:                int lineStart = getLineStartOffset(line);
0412:                int offset = Math.max(0, Math.min(getLineLength(line) - 1,
0413:                        getCaretPosition() - lineStart));
0414:
0415:                return scrollTo(line, offset);
0416:            }
0417:
0418:            /**
0419:             * Ensures that the specified line and offset is visible by scrolling
0420:             * the text area if necessary.
0421:             * @param line The line to scroll to
0422:             * @param offset The offset in the line to scroll to
0423:             * @return True if scrolling was actually performed, false if the
0424:             * line and offset was already visible
0425:             */
0426:            public boolean scrollTo(int line, int offset) {
0427:                // visibleLines == 0 before the component is realized
0428:                // we can't do any proper scrolling then, so we have
0429:                // this hack...
0430:                if (visibleLines == 0) {
0431:                    setFirstLine(Math.max(0, line - electricScroll));
0432:                    return true;
0433:                }
0434:
0435:                int newFirstLine = firstLine;
0436:                int newHorizontalOffset = horizontalOffset;
0437:
0438:                if (line < firstLine + electricScroll) {
0439:                    newFirstLine = Math.max(0, line - electricScroll);
0440:                } else if (line + electricScroll >= firstLine + visibleLines) {
0441:                    newFirstLine = (line - visibleLines) + electricScroll + 1;
0442:                    if (newFirstLine + visibleLines >= getLineCount())
0443:                        newFirstLine = getLineCount() - visibleLines;
0444:                    if (newFirstLine < 0)
0445:                        newFirstLine = 0;
0446:                }
0447:
0448:                int x = _offsetToX(line, offset);
0449:                int width = painter.getFontMetrics().charWidth('w');
0450:
0451:                if (x < 0) {
0452:                    newHorizontalOffset = Math.min(0, horizontalOffset - x
0453:                            + width + 5);
0454:                } else if (x + width >= painter.getWidth()) {
0455:                    newHorizontalOffset = horizontalOffset
0456:                            + (painter.getWidth() - x) - width - 5;
0457:                }
0458:
0459:                return setOrigin(newFirstLine, newHorizontalOffset);
0460:            }
0461:
0462:            /**
0463:             * Converts a line index to a y co-ordinate.
0464:             * @param line The line
0465:             */
0466:            public int lineToY(int line) {
0467:                FontMetrics fm = painter.getFontMetrics();
0468:                return (line - firstLine) * fm.getHeight()
0469:                        - (fm.getLeading() + fm.getMaxDescent());
0470:            }
0471:
0472:            /**
0473:             * Converts a y co-ordinate to a line index.
0474:             * @param y The y co-ordinate
0475:             */
0476:            public int yToLine(int y) {
0477:                FontMetrics fm = painter.getFontMetrics();
0478:                int height = fm.getHeight();
0479:                return Math.max(0, Math.min(getLineCount() - 1, y / height
0480:                        + firstLine));
0481:            }
0482:
0483:            /**
0484:             * Converts an offset in a line into an x co-ordinate. This is a
0485:             * slow version that can be used any time.
0486:             * @param line The line
0487:             * @param offset The offset, from the start of the line
0488:             */
0489:            public final int offsetToX(int line, int offset) {
0490:                // don't use cached tokens
0491:                painter.currentLineTokens = null;
0492:                return _offsetToX(line, offset);
0493:            }
0494:
0495:            /**
0496:             * Converts an offset in a line into an x co-ordinate. This is a
0497:             * fast version that should only be used if no changes were made
0498:             * to the text since the last repaint.
0499:             * @param line The line
0500:             * @param offset The offset, from the start of the line
0501:             */
0502:            public int _offsetToX(int line, int offset) {
0503:                TokenMarker tokenMarker = getTokenMarker();
0504:
0505:                /* Use painter's cached info for speed */
0506:                FontMetrics fm = painter.getFontMetrics();
0507:
0508:                getLineText(line, lineSegment);
0509:
0510:                int segmentOffset = lineSegment.offset;
0511:                int x = horizontalOffset;
0512:
0513:                /* If syntax coloring is disabled, do simple translation */
0514:                if (tokenMarker == null) {
0515:                    lineSegment.count = offset;
0516:                    return x
0517:                            + Utilities.getTabbedTextWidth(lineSegment, fm, x,
0518:                                    painter, 0);
0519:                }
0520:                /* If syntax coloring is enabled, we have to do this because
0521:                 * tokens can vary in width */
0522:                else {
0523:                    Token tokens;
0524:                    if (painter.currentLineIndex == line
0525:                            && painter.currentLineTokens != null)
0526:                        tokens = painter.currentLineTokens;
0527:                    else {
0528:                        painter.currentLineIndex = line;
0529:                        tokens = painter.currentLineTokens = tokenMarker
0530:                                .markTokens(lineSegment, line);
0531:                    }
0532:
0533:                    Toolkit toolkit = painter.getToolkit();
0534:                    Font defaultFont = painter.getFont();
0535:                    SyntaxStyle[] styles = painter.getStyles();
0536:
0537:                    for (;;) {
0538:                        byte id = tokens.id;
0539:                        if (id == Token.END) {
0540:                            return x;
0541:                        }
0542:
0543:                        if (id == Token.NULL)
0544:                            fm = painter.getFontMetrics();
0545:                        else
0546:                            fm = styles[id].getFontMetrics(defaultFont);
0547:
0548:                        int length = tokens.length;
0549:
0550:                        if (offset + segmentOffset < lineSegment.offset
0551:                                + length) {
0552:                            lineSegment.count = offset
0553:                                    - (lineSegment.offset - segmentOffset);
0554:                            return x
0555:                                    + Utilities.getTabbedTextWidth(lineSegment,
0556:                                            fm, x, painter, 0);
0557:                        } else {
0558:                            lineSegment.count = length;
0559:                            x += Utilities.getTabbedTextWidth(lineSegment, fm,
0560:                                    x, painter, 0);
0561:                            lineSegment.offset += length;
0562:                        }
0563:                        tokens = tokens.next;
0564:                    }
0565:                }
0566:            }
0567:
0568:            /**
0569:             * Converts an x co-ordinate to an offset within a line.
0570:             * @param line The line
0571:             * @param x The x co-ordinate
0572:             */
0573:            public int xToOffset(int line, int x) {
0574:                TokenMarker tokenMarker = getTokenMarker();
0575:
0576:                /* Use painter's cached info for speed */
0577:                FontMetrics fm = painter.getFontMetrics();
0578:
0579:                getLineText(line, lineSegment);
0580:
0581:                char[] segmentArray = lineSegment.array;
0582:                int segmentOffset = lineSegment.offset;
0583:                int segmentCount = lineSegment.count;
0584:
0585:                int width = horizontalOffset;
0586:
0587:                if (tokenMarker == null) {
0588:                    for (int i = 0; i < segmentCount; i++) {
0589:                        char c = segmentArray[i + segmentOffset];
0590:                        int charWidth;
0591:                        if (c == '\t')
0592:                            charWidth = (int) painter.nextTabStop(width, i)
0593:                                    - width;
0594:                        else
0595:                            charWidth = fm.charWidth(c);
0596:
0597:                        if (painter.isBlockCaretEnabled()) {
0598:                            if (x - charWidth <= width)
0599:                                return i;
0600:                        } else {
0601:                            if (x - charWidth / 2 <= width)
0602:                                return i;
0603:                        }
0604:
0605:                        width += charWidth;
0606:                    }
0607:
0608:                    return segmentCount;
0609:                } else {
0610:                    Token tokens;
0611:                    if (painter.currentLineIndex == line
0612:                            && painter.currentLineTokens != null)
0613:                        tokens = painter.currentLineTokens;
0614:                    else {
0615:                        painter.currentLineIndex = line;
0616:                        tokens = painter.currentLineTokens = tokenMarker
0617:                                .markTokens(lineSegment, line);
0618:                    }
0619:
0620:                    int offset = 0;
0621:                    Toolkit toolkit = painter.getToolkit();
0622:                    Font defaultFont = painter.getFont();
0623:                    SyntaxStyle[] styles = painter.getStyles();
0624:
0625:                    for (;;) {
0626:                        byte id = tokens.id;
0627:                        if (id == Token.END)
0628:                            return offset;
0629:
0630:                        if (id == Token.NULL)
0631:                            fm = painter.getFontMetrics();
0632:                        else
0633:                            fm = styles[id].getFontMetrics(defaultFont);
0634:
0635:                        int length = tokens.length;
0636:
0637:                        for (int i = 0; i < length; i++) {
0638:                            char c = segmentArray[segmentOffset + offset + i];
0639:                            int charWidth;
0640:                            if (c == '\t')
0641:                                charWidth = (int) painter.nextTabStop(width,
0642:                                        offset + i)
0643:                                        - width;
0644:                            else
0645:                                charWidth = fm.charWidth(c);
0646:
0647:                            if (painter.isBlockCaretEnabled()) {
0648:                                if (x - charWidth <= width)
0649:                                    return offset + i;
0650:                            } else {
0651:                                if (x - charWidth / 2 <= width)
0652:                                    return offset + i;
0653:                            }
0654:
0655:                            width += charWidth;
0656:                        }
0657:
0658:                        offset += length;
0659:                        tokens = tokens.next;
0660:                    }
0661:                }
0662:            }
0663:
0664:            /**
0665:             * Converts a point to an offset, from the start of the text.
0666:             * @param x The x co-ordinate of the point
0667:             * @param y The y co-ordinate of the point
0668:             */
0669:            public int xyToOffset(int x, int y) {
0670:                int line = yToLine(y);
0671:                int start = getLineStartOffset(line);
0672:                return start + xToOffset(line, x);
0673:            }
0674:
0675:            /**
0676:             * Returns the document this text area is editing.
0677:             */
0678:            public final SyntaxDocument getDocument() {
0679:                return document;
0680:            }
0681:
0682:            /**
0683:             * Sets the document this text area is editing.
0684:             * @param document The document
0685:             */
0686:            public void setDocument(SyntaxDocument document) {
0687:                if (this .document == document)
0688:                    return;
0689:                if (this .document != null)
0690:                    this .document.removeDocumentListener(documentHandler);
0691:                this .document = document;
0692:
0693:                document.addDocumentListener(documentHandler);
0694:
0695:                select(0, 0);
0696:                updateScrollBars();
0697:                painter.repaint();
0698:                gutter.repaint();
0699:            }
0700:
0701:            /**
0702:             * Returns the document's token marker. Equivalent to calling
0703:             * <code>getDocument().getTokenMarker()</code>.
0704:             */
0705:            public final TokenMarker getTokenMarker() {
0706:                return document.getTokenMarker();
0707:            }
0708:
0709:            /**
0710:             * Sets the document's token marker. Equivalent to caling
0711:             * <code>getDocument().setTokenMarker()</code>.
0712:             * @param tokenMarker The token marker
0713:             */
0714:            public final void setTokenMarker(TokenMarker tokenMarker) {
0715:                document.setTokenMarker(tokenMarker);
0716:            }
0717:
0718:            /**
0719:             * Returns the length of the document. Equivalent to calling
0720:             * <code>getDocument().getLength()</code>.
0721:             */
0722:            public final int getDocumentLength() {
0723:                return document.getLength();
0724:            }
0725:
0726:            /**
0727:             * Returns the number of lines in the document.
0728:             */
0729:            public final int getLineCount() {
0730:                return document.getDefaultRootElement().getElementCount();
0731:            }
0732:
0733:            /**
0734:             * Returns the line containing the specified offset.
0735:             * @param offset The offset
0736:             */
0737:            public final int getLineOfOffset(int offset) {
0738:                return document.getDefaultRootElement().getElementIndex(offset);
0739:            }
0740:
0741:            /**
0742:             * Returns the start offset of the specified line.
0743:             * @param line The line
0744:             * @return The start offset of the specified line, or -1 if the line is
0745:             * invalid
0746:             */
0747:            public int getLineStartOffset(int line) {
0748:                Element lineElement = document.getDefaultRootElement()
0749:                        .getElement(line);
0750:                if (lineElement == null)
0751:                    return -1;
0752:                else
0753:                    return lineElement.getStartOffset();
0754:            }
0755:
0756:            /**
0757:             * Returns the end offset of the specified line.
0758:             * @param line The line
0759:             * @return The end offset of the specified line, or -1 if the line is
0760:             * invalid.
0761:             */
0762:            public int getLineEndOffset(int line) {
0763:                Element lineElement = document.getDefaultRootElement()
0764:                        .getElement(line);
0765:                if (lineElement == null)
0766:                    return -1;
0767:                else
0768:                    return lineElement.getEndOffset();
0769:            }
0770:
0771:            /**
0772:             * Returns the length of the specified line.
0773:             * @param line The line
0774:             */
0775:            public int getLineLength(int line) {
0776:                Element lineElement = document.getDefaultRootElement()
0777:                        .getElement(line);
0778:                if (lineElement == null)
0779:                    return -1;
0780:                else
0781:                    return lineElement.getEndOffset()
0782:                            - lineElement.getStartOffset() - 1;
0783:            }
0784:
0785:            /**
0786:             * Returns the entire text of this text area.
0787:             */
0788:            public String getText() {
0789:                try {
0790:                    return document.getText(0, document.getLength());
0791:                } catch (BadLocationException bl) {
0792:                    bl.printStackTrace();
0793:                    return null;
0794:                }
0795:            }
0796:
0797:            /**
0798:             * Sets the entire text of this text area.
0799:             */
0800:            public void setText(String text) {
0801:                if (document == null)
0802:                    return;
0803:
0804:                try {
0805:                    document.beginCompoundEdit();
0806:                    document.remove(0, document.getLength());
0807:                    document.insertString(0, text, null);
0808:                } catch (BadLocationException bl) {
0809:                    bl.printStackTrace();
0810:                } finally {
0811:                    document.endCompoundEdit();
0812:                }
0813:            }
0814:
0815:            /**
0816:             * Returns the specified substring of the document.
0817:             * @param start The start offset
0818:             * @param len The length of the substring
0819:             * @return The substring, or null if the offsets are invalid
0820:             */
0821:            public final String getText(int start, int len) {
0822:                try {
0823:                    return document.getText(start, len);
0824:                } catch (BadLocationException bl) {
0825:                    bl.printStackTrace();
0826:                    return null;
0827:                }
0828:            }
0829:
0830:            /**
0831:             * Copies the specified substring of the document into a segment.
0832:             * If the offsets are invalid, the segment will contain a null string.
0833:             * @param start The start offset
0834:             * @param len The length of the substring
0835:             * @param segment The segment
0836:             */
0837:            public final void getText(int start, int len, Segment segment) {
0838:                try {
0839:                    document.getText(start, len, segment);
0840:                } catch (BadLocationException bl) {
0841:                    bl.printStackTrace();
0842:                    segment.offset = segment.count = 0;
0843:                }
0844:            }
0845:
0846:            /**
0847:             * Returns the text on the specified line.
0848:             * @param lineIndex The line
0849:             * @return The text, or null if the line is invalid
0850:             */
0851:            public final String getLineText(int lineIndex) {
0852:                int start = getLineStartOffset(lineIndex);
0853:                return getText(start, getLineEndOffset(lineIndex) - start - 1);
0854:            }
0855:
0856:            /**
0857:             * Copies the text on the specified line into a segment. If the line
0858:             * is invalid, the segment will contain a null string.
0859:             * @param lineIndex The line
0860:             */
0861:            public final void getLineText(int lineIndex, Segment segment) {
0862:                int start = getLineStartOffset(lineIndex);
0863:                getText(start, getLineEndOffset(lineIndex) - start - 1, segment);
0864:            }
0865:
0866:            /**
0867:             * Returns the selection start offset.
0868:             */
0869:            public final int getSelectionStart() {
0870:                return selectionStart;
0871:            }
0872:
0873:            /**
0874:             * Returns the offset where the selection starts on the specified
0875:             * line.
0876:             */
0877:            public int getSelectionStart(int line) {
0878:                if (line == selectionStartLine)
0879:                    return selectionStart;
0880:                else if (rectSelect) {
0881:                    Element map = document.getDefaultRootElement();
0882:                    int start = selectionStart
0883:                            - map.getElement(selectionStartLine)
0884:                                    .getStartOffset();
0885:
0886:                    Element lineElement = map.getElement(line);
0887:                    int lineStart = lineElement.getStartOffset();
0888:                    int lineEnd = lineElement.getEndOffset() - 1;
0889:                    return Math.min(lineEnd, lineStart + start);
0890:                } else
0891:                    return getLineStartOffset(line);
0892:            }
0893:
0894:            /**
0895:             * Returns the selection start line.
0896:             */
0897:            public final int getSelectionStartLine() {
0898:                return selectionStartLine;
0899:            }
0900:
0901:            /**
0902:             * Sets the selection start. The new selection will be the new
0903:             * selection start and the old selection end.
0904:             * @param selectionStart The selection start
0905:             * @see #select(int,int)
0906:             */
0907:            public final void setSelectionStart(int selectionStart) {
0908:                select(selectionStart, selectionEnd);
0909:            }
0910:
0911:            /**
0912:             * Returns the selection end offset.
0913:             */
0914:            public final int getSelectionEnd() {
0915:                return selectionEnd;
0916:            }
0917:
0918:            /**
0919:             * Returns the offset where the selection ends on the specified
0920:             * line.
0921:             */
0922:            public int getSelectionEnd(int line) {
0923:                if (line == selectionEndLine)
0924:                    return selectionEnd;
0925:                else if (rectSelect) {
0926:                    Element map = document.getDefaultRootElement();
0927:                    int end = selectionEnd
0928:                            - map.getElement(selectionEndLine).getStartOffset();
0929:
0930:                    Element lineElement = map.getElement(line);
0931:                    int lineStart = lineElement.getStartOffset();
0932:                    int lineEnd = lineElement.getEndOffset() - 1;
0933:                    return Math.min(lineEnd, lineStart + end);
0934:                } else
0935:                    return getLineEndOffset(line) - 1;
0936:            }
0937:
0938:            /**
0939:             * Returns the selection end line.
0940:             */
0941:            public final int getSelectionEndLine() {
0942:                return selectionEndLine;
0943:            }
0944:
0945:            /**
0946:             * Sets the selection end. The new selection will be the old
0947:             * selection start and the bew selection end.
0948:             * @param selectionEnd The selection end
0949:             * @see #select(int,int)
0950:             */
0951:            public final void setSelectionEnd(int selectionEnd) {
0952:                select(selectionStart, selectionEnd);
0953:            }
0954:
0955:            /**
0956:             * Returns the caret position. This will either be the selection
0957:             * start or the selection end, depending on which direction the
0958:             * selection was made in.
0959:             */
0960:            public final int getCaretPosition() {
0961:                return (biasLeft ? selectionStart : selectionEnd);
0962:            }
0963:
0964:            /**
0965:             * Returns the caret line.
0966:             */
0967:            public final int getCaretLine() {
0968:                return (biasLeft ? selectionStartLine : selectionEndLine);
0969:            }
0970:
0971:            /**
0972:             * Returns the mark position. This will be the opposite selection
0973:             * bound to the caret position.
0974:             * @see #getCaretPosition()
0975:             */
0976:            public final int getMarkPosition() {
0977:                return (biasLeft ? selectionEnd : selectionStart);
0978:            }
0979:
0980:            /**
0981:             * Returns the mark line.
0982:             */
0983:            public final int getMarkLine() {
0984:                return (biasLeft ? selectionEndLine : selectionStartLine);
0985:            }
0986:
0987:            /**
0988:             * Sets the caret position. The new selection will consist of the
0989:             * caret position only (hence no text will be selected)
0990:             * @param caret The caret position
0991:             * @see #select(int,int)
0992:             */
0993:            public final void setCaretPosition(int caret) {
0994:                select(caret, caret);
0995:            }
0996:
0997:            /**
0998:             * Selects all text in the document.
0999:             */
1000:            public final void selectAll() {
1001:                select(0, getDocumentLength());
1002:            }
1003:
1004:            /**
1005:             * Moves the mark to the caret position.
1006:             */
1007:            public final void selectNone() {
1008:                select(getCaretPosition(), getCaretPosition());
1009:            }
1010:
1011:            /**
1012:             * Selects from the start offset to the end offset. This is the
1013:             * general selection method used by all other selecting methods.
1014:             * The caret position will be start if start &lt; end, and end
1015:             * if end &gt; start.
1016:             * @param start The start offset
1017:             * @param end The end offset
1018:             */
1019:            public void select(int start, int end) {
1020:                int newStart, newEnd;
1021:                boolean newBias;
1022:                if (start <= end) {
1023:                    newStart = start;
1024:                    newEnd = end;
1025:                    newBias = false;
1026:                } else {
1027:                    newStart = end;
1028:                    newEnd = start;
1029:                    newBias = true;
1030:                }
1031:
1032:                if (newStart < 0 || newEnd > getDocumentLength()) {
1033:                    throw new IllegalArgumentException("Bounds out of"
1034:                            + " range: " + newStart + "," + newEnd);
1035:                }
1036:
1037:                // If the new position is the same as the old, we don't
1038:                // do all this crap, however we still do the stuff at
1039:                // the end (clearing magic position, scrolling)
1040:                if (newStart != selectionStart || newEnd != selectionEnd
1041:                        || newBias != biasLeft) {
1042:                    int newStartLine = getLineOfOffset(newStart);
1043:                    int newEndLine = getLineOfOffset(newEnd);
1044:
1045:                    if (painter.isBracketHighlightEnabled()) {
1046:                        if (bracketLine != -1)
1047:                            painter.invalidateLine(bracketLine);
1048:                        updateBracketHighlight(end);
1049:                        if (bracketLine != -1)
1050:                            painter.invalidateLine(bracketLine);
1051:                    }
1052:
1053:                    painter.invalidateLineRange(selectionStartLine,
1054:                            selectionEndLine);
1055:                    painter.invalidateLineRange(newStartLine, newEndLine);
1056:
1057:                    document.addUndoableEdit(new CaretUndo(selectionStart,
1058:                            selectionEnd));
1059:
1060:                    selectionStart = newStart;
1061:                    selectionEnd = newEnd;
1062:                    selectionStartLine = newStartLine;
1063:                    selectionEndLine = newEndLine;
1064:                    biasLeft = newBias;
1065:
1066:                    fireCaretEvent();
1067:                }
1068:
1069:                // When the user is typing, etc, we don't want the caret
1070:                // to blink
1071:                blink = true;
1072:                caretTimer.restart();
1073:
1074:                // Disable rectangle select if selection start = selection end
1075:                if (selectionStart == selectionEnd)
1076:                    rectSelect = false;
1077:
1078:                // Clear the `magic' caret position used by up/down
1079:                magicCaret = -1;
1080:
1081:                scrollToCaret();
1082:            }
1083:
1084:            /**
1085:             * Returns the selected text, or null if no selection is active.
1086:             */
1087:            public final String getSelectedText() {
1088:                if (selectionStart == selectionEnd)
1089:                    return null;
1090:
1091:                if (rectSelect) {
1092:                    // Return each row of the selection on a new line
1093:
1094:                    Element map = document.getDefaultRootElement();
1095:
1096:                    int start = selectionStart
1097:                            - map.getElement(selectionStartLine)
1098:                                    .getStartOffset();
1099:                    int end = selectionEnd
1100:                            - map.getElement(selectionEndLine).getStartOffset();
1101:
1102:                    // Certain rectangles satisfy this condition...
1103:                    if (end < start) {
1104:                        int tmp = end;
1105:                        end = start;
1106:                        start = tmp;
1107:                    }
1108:
1109:                    StringBuffer buf = new StringBuffer();
1110:                    Segment seg = new Segment();
1111:
1112:                    for (int i = selectionStartLine; i <= selectionEndLine; i++) {
1113:                        Element lineElement = map.getElement(i);
1114:                        int lineStart = lineElement.getStartOffset();
1115:                        int lineEnd = lineElement.getEndOffset() - 1;
1116:                        int lineLen = lineEnd - lineStart;
1117:
1118:                        lineStart = Math.min(lineStart + start, lineEnd);
1119:                        lineLen = Math.min(end - start, lineEnd - lineStart);
1120:
1121:                        getText(lineStart, lineLen, seg);
1122:                        buf.append(seg.array, seg.offset, seg.count);
1123:
1124:                        if (i != selectionEndLine)
1125:                            buf.append('\n');
1126:                    }
1127:
1128:                    return buf.toString();
1129:                } else {
1130:                    return getText(selectionStart, selectionEnd
1131:                            - selectionStart);
1132:                }
1133:            }
1134:
1135:            /**
1136:             * Replaces the selection with the specified text.
1137:             * @param selectedText The replacement text for the selection
1138:             */
1139:            public void setSelectedText(String selectedText) {
1140:                if (!editable) {
1141:                    throw new InternalError("Text component" + " read only");
1142:                }
1143:
1144:                document.beginCompoundEdit();
1145:
1146:                try {
1147:                    if (rectSelect) {
1148:                        Element map = document.getDefaultRootElement();
1149:
1150:                        int start = selectionStart
1151:                                - map.getElement(selectionStartLine)
1152:                                        .getStartOffset();
1153:                        int end = selectionEnd
1154:                                - map.getElement(selectionEndLine)
1155:                                        .getStartOffset();
1156:
1157:                        // Certain rectangles satisfy this condition...
1158:                        if (end < start) {
1159:                            int tmp = end;
1160:                            end = start;
1161:                            start = tmp;
1162:                        }
1163:
1164:                        int lastNewline = 0;
1165:                        int currNewline = 0;
1166:
1167:                        for (int i = selectionStartLine; i <= selectionEndLine; i++) {
1168:                            Element lineElement = map.getElement(i);
1169:                            int lineStart = lineElement.getStartOffset();
1170:                            int lineEnd = lineElement.getEndOffset() - 1;
1171:                            int rectStart = Math
1172:                                    .min(lineEnd, lineStart + start);
1173:
1174:                            document.remove(rectStart, Math.min(lineEnd
1175:                                    - rectStart, end - start));
1176:
1177:                            if (selectedText == null)
1178:                                continue;
1179:
1180:                            currNewline = selectedText.indexOf('\n',
1181:                                    lastNewline);
1182:                            if (currNewline == -1)
1183:                                currNewline = selectedText.length();
1184:
1185:                            document.insertString(rectStart, selectedText
1186:                                    .substring(lastNewline, currNewline), null);
1187:
1188:                            lastNewline = Math.min(selectedText.length(),
1189:                                    currNewline + 1);
1190:                        }
1191:
1192:                        if (selectedText != null
1193:                                && currNewline != selectedText.length()) {
1194:                            int offset = map.getElement(selectionEndLine)
1195:                                    .getEndOffset() - 1;
1196:                            document.insertString(offset, "\n", null);
1197:                            document.insertString(offset + 1, selectedText
1198:                                    .substring(currNewline + 1), null);
1199:                        }
1200:                    } else {
1201:                        document.remove(selectionStart, selectionEnd
1202:                                - selectionStart);
1203:                        if (selectedText != null) {
1204:                            document.insertString(selectionStart, selectedText,
1205:                                    null);
1206:                        }
1207:                    }
1208:                } catch (BadLocationException bl) {
1209:                    bl.printStackTrace();
1210:                    throw new InternalError("Cannot replace" + " selection");
1211:                }
1212:                // No matter what happends... stops us from leaving document
1213:                // in a bad state
1214:                finally {
1215:                    document.endCompoundEdit();
1216:                }
1217:
1218:                setCaretPosition(selectionEnd);
1219:            }
1220:
1221:            /**
1222:             * Returns true if this text area is editable, false otherwise.
1223:             */
1224:            public final boolean isEditable() {
1225:                return editable;
1226:            }
1227:
1228:            /**
1229:             * Sets if this component is editable.
1230:             * @param editable True if this text area should be editable,
1231:             * false otherwise
1232:             */
1233:            public final void setEditable(boolean editable) {
1234:                this .editable = editable;
1235:            }
1236:
1237:            /**
1238:             * Returns the right click popup menu.
1239:             */
1240:            public final JPopupMenu getRightClickPopup() {
1241:                return popup;
1242:            }
1243:
1244:            /**
1245:             * Sets the right click popup menu.
1246:             * @param popup The popup
1247:             */
1248:            public final void setRightClickPopup(JPopupMenu popup) {
1249:                this .popup = popup;
1250:            }
1251:
1252:            /**
1253:             * Returns the `magic' caret position. This can be used to preserve
1254:             * the column position when moving up and down lines.
1255:             */
1256:            public final int getMagicCaretPosition() {
1257:                return magicCaret;
1258:            }
1259:
1260:            /**
1261:             * Sets the `magic' caret position. This can be used to preserve
1262:             * the column position when moving up and down lines.
1263:             * @param magicCaret The magic caret position
1264:             */
1265:            public final void setMagicCaretPosition(int magicCaret) {
1266:                this .magicCaret = magicCaret;
1267:            }
1268:
1269:            /**
1270:             * Similar to <code>setSelectedText()</code>, but overstrikes the
1271:             * appropriate number of characters if overwrite mode is enabled.
1272:             * @param str The string
1273:             * @see #setSelectedText(String)
1274:             * @see #isOverwriteEnabled()
1275:             */
1276:            public void overwriteSetSelectedText(String str) {
1277:                // Don't overstrike if there is a selection
1278:                if (!overwrite || selectionStart != selectionEnd) {
1279:                    setSelectedText(str);
1280:                    return;
1281:                }
1282:
1283:                // Don't overstrike if we're on the end of
1284:                // the line
1285:                int caret = getCaretPosition();
1286:                int caretLineEnd = getLineEndOffset(getCaretLine());
1287:                if (caretLineEnd - caret <= str.length()) {
1288:                    setSelectedText(str);
1289:                    return;
1290:                }
1291:
1292:                document.beginCompoundEdit();
1293:
1294:                try {
1295:                    document.remove(caret, str.length());
1296:                    document.insertString(caret, str, null);
1297:                } catch (BadLocationException bl) {
1298:                    bl.printStackTrace();
1299:                } finally {
1300:                    document.endCompoundEdit();
1301:                }
1302:            }
1303:
1304:            /**
1305:             * Returns true if overwrite mode is enabled, false otherwise.
1306:             */
1307:            public final boolean isOverwriteEnabled() {
1308:                return overwrite;
1309:            }
1310:
1311:            /**
1312:             * Sets if overwrite mode should be enabled.
1313:             * @param overwrite True if overwrite mode should be enabled,
1314:             * false otherwise.
1315:             */
1316:            public final void setOverwriteEnabled(boolean overwrite) {
1317:                this .overwrite = overwrite;
1318:                painter.invalidateSelectedLines();
1319:            }
1320:
1321:            /**
1322:             * Returns true if the selection is rectangular, false otherwise.
1323:             */
1324:            public final boolean isSelectionRectangular() {
1325:                return rectSelect;
1326:            }
1327:
1328:            /**
1329:             * Sets if the selection should be rectangular.
1330:             * @param overwrite True if the selection should be rectangular,
1331:             * false otherwise.
1332:             */
1333:            public final void setSelectionRectangular(boolean rectSelect) {
1334:                this .rectSelect = rectSelect;
1335:                painter.invalidateSelectedLines();
1336:            }
1337:
1338:            /**
1339:             * Returns the position of the highlighted bracket (the bracket
1340:             * matching the one before the caret)
1341:             */
1342:            public final int getBracketPosition() {
1343:                return bracketPosition;
1344:            }
1345:
1346:            /**
1347:             * Returns the line of the highlighted bracket (the bracket
1348:             * matching the one before the caret)
1349:             */
1350:            public final int getBracketLine() {
1351:                return bracketLine;
1352:            }
1353:
1354:            /**
1355:             * Adds a caret change listener to this text area.
1356:             * @param listener The listener
1357:             */
1358:            public final void addCaretListener(CaretListener listener) {
1359:                listenerList.add(CaretListener.class, listener);
1360:            }
1361:
1362:            /**
1363:             * Removes a caret change listener from this text area.
1364:             * @param listener The listener
1365:             */
1366:            public final void removeCaretListener(CaretListener listener) {
1367:                listenerList.remove(CaretListener.class, listener);
1368:            }
1369:
1370:            /**
1371:             * Deletes the selected text from the text area and places it
1372:             * into the clipboard.
1373:             */
1374:            public void cut() {
1375:                if (editable) {
1376:                    copy();
1377:                    setSelectedText("");
1378:                }
1379:            }
1380:
1381:            /**
1382:             * Places the selected text into the clipboard.
1383:             */
1384:            public void copy() {
1385:                if (selectionStart != selectionEnd) {
1386:                    Clipboard clipboard = getToolkit().getSystemClipboard();
1387:
1388:                    String selection = getSelectedText();
1389:
1390:                    int repeatCount = inputHandler.getRepeatCount();
1391:                    StringBuffer buf = new StringBuffer();
1392:                    for (int i = 0; i < repeatCount; i++)
1393:                        buf.append(selection);
1394:
1395:                    clipboard.setContents(new StringSelection(buf.toString()),
1396:                            null);
1397:                }
1398:            }
1399:
1400:            /**
1401:             * Inserts the clipboard contents into the text.
1402:             */
1403:            public void paste() {
1404:                if (editable) {
1405:                    Clipboard clipboard = getToolkit().getSystemClipboard();
1406:                    try {
1407:                        // The MacOS MRJ doesn't convert \r to \n,
1408:                        // so do it here
1409:                        String selection = ((String) clipboard
1410:                                .getContents(this ).getTransferData(
1411:                                        DataFlavor.stringFlavor)).replace('\r',
1412:                                '\n');
1413:
1414:                        int repeatCount = inputHandler.getRepeatCount();
1415:                        StringBuffer buf = new StringBuffer();
1416:                        for (int i = 0; i < repeatCount; i++)
1417:                            buf.append(selection);
1418:                        selection = buf.toString();
1419:                        setSelectedText(selection);
1420:                    } catch (Exception e) {
1421:                        getToolkit().beep();
1422:                        System.err.println("Clipboard does not"
1423:                                + " contain a string");
1424:                    }
1425:                }
1426:            }
1427:
1428:            /**
1429:             * Called by the AWT when this component is removed from it's parent.
1430:             * This stops clears the currently focused component.
1431:             */
1432:            public void removeNotify() {
1433:                super .removeNotify();
1434:                if (focusedComponent == this )
1435:                    focusedComponent = null;
1436:            }
1437:
1438:            /**
1439:             * Forwards key events directly to the input handler.
1440:             * This is slightly faster than using a KeyListener
1441:             * because some Swing overhead is avoided.
1442:             */
1443:            public void processKeyEvent(KeyEvent evt) {
1444:                if (inputHandler == null)
1445:                    return;
1446:                switch (evt.getKeyCode()) {
1447:                case KeyEvent.VK_F1:
1448:                case KeyEvent.VK_F2:
1449:                case KeyEvent.VK_F3:
1450:                case KeyEvent.VK_F4:
1451:                case KeyEvent.VK_F5:
1452:                case KeyEvent.VK_F6:
1453:                case KeyEvent.VK_F7:
1454:                case KeyEvent.VK_F8:
1455:                case KeyEvent.VK_F9:
1456:                case KeyEvent.VK_F10:
1457:                case KeyEvent.VK_F11:
1458:                case KeyEvent.VK_F12:
1459:                    super .processKeyEvent(evt);
1460:                    return;
1461:                }
1462:                switch (evt.getID()) {
1463:                case KeyEvent.KEY_TYPED:
1464:                    inputHandler.keyTyped(evt);
1465:                    break;
1466:                case KeyEvent.KEY_PRESSED:
1467:                    inputHandler.keyPressed(evt);
1468:                    processMetaKey(evt);
1469:                    break;
1470:                case KeyEvent.KEY_RELEASED:
1471:                    inputHandler.keyReleased(evt);
1472:                    break;
1473:                }
1474:            }
1475:
1476:            public void processMetaKey(KeyEvent evt) {
1477:                super .processKeyEvent(evt);
1478:            }
1479:
1480:            /**
1481:             * Returns true if the bracket highlight is visible, false otherwise.
1482:             */
1483:            final boolean isBracketHighlightVisible() {
1484:                return ((bracketLine != -1) && hasFocus());
1485:            }
1486:
1487:            // protected members
1488:            protected static String CENTER = "center";
1489:            protected static String LEFT = "left";
1490:            protected static String RIGHT = "right";
1491:            protected static String BOTTOM = "bottom";
1492:
1493:            protected static JEditTextArea focusedComponent;
1494:            protected static Timer caretTimer;
1495:
1496:            protected TextAreaPainter painter;
1497:            private Gutter gutter;
1498:
1499:            protected JPopupMenu popup;
1500:
1501:            protected EventListenerList listenerList;
1502:            protected MutableCaretEvent caretEvent;
1503:
1504:            protected boolean caretBlinks;
1505:            protected boolean caretVisible;
1506:            protected boolean blink;
1507:
1508:            protected boolean editable;
1509:
1510:            protected int firstLine;
1511:            protected int visibleLines;
1512:            protected int electricScroll;
1513:
1514:            protected int horizontalOffset;
1515:
1516:            protected JScrollBar vertical;
1517:            protected JScrollBar horizontal;
1518:            protected boolean scrollBarsInitialized;
1519:
1520:            protected InputHandler inputHandler;
1521:            protected SyntaxDocument document;
1522:            protected DocumentHandler documentHandler;
1523:
1524:            protected Segment lineSegment;
1525:
1526:            protected int selectionStart;
1527:            protected int selectionStartLine;
1528:            protected int selectionEnd;
1529:            protected int selectionEndLine;
1530:            protected boolean biasLeft;
1531:
1532:            protected int bracketPosition;
1533:            protected int bracketLine;
1534:
1535:            protected int magicCaret;
1536:            protected boolean overwrite;
1537:            protected boolean rectSelect;
1538:
1539:            protected void fireCaretEvent() {
1540:                Object[] listeners = listenerList.getListenerList();
1541:                for (int i = listeners.length - 2; i >= 0; i--) {
1542:                    if (listeners[i] == CaretListener.class) {
1543:                        ((CaretListener) listeners[i + 1])
1544:                                .caretUpdate(caretEvent);
1545:                    }
1546:                }
1547:            }
1548:
1549:            protected void updateBracketHighlight(int newCaretPosition) {
1550:                if (newCaretPosition == 0) {
1551:                    bracketPosition = bracketLine = -1;
1552:                    return;
1553:                }
1554:
1555:                try {
1556:                    int offset = TextUtilities.findMatchingBracket(document,
1557:                            newCaretPosition - 1);
1558:                    if (offset != -1) {
1559:                        bracketLine = getLineOfOffset(offset);
1560:                        bracketPosition = offset
1561:                                - getLineStartOffset(bracketLine);
1562:                        return;
1563:                    }
1564:                } catch (BadLocationException bl) {
1565:                    bl.printStackTrace();
1566:                }
1567:
1568:                bracketLine = bracketPosition = -1;
1569:            }
1570:
1571:            protected void documentChanged(DocumentEvent evt) {
1572:                DocumentEvent.ElementChange ch = evt.getChange(document
1573:                        .getDefaultRootElement());
1574:
1575:                int count;
1576:                if (ch == null)
1577:                    count = 0;
1578:                else
1579:                    count = ch.getChildrenAdded().length
1580:                            - ch.getChildrenRemoved().length;
1581:
1582:                int line = getLineOfOffset(evt.getOffset());
1583:                if (count == 0) {
1584:                    painter.invalidateLine(line);
1585:                }
1586:                // do magic stuff
1587:                else if (line < firstLine) {
1588:                    setFirstLine(firstLine + count);
1589:                }
1590:                // end of magic stuff
1591:                else {
1592:                    painter.invalidateLineRange(line, firstLine + visibleLines);
1593:                    updateScrollBars();
1594:                }
1595:            }
1596:
1597:            class ScrollLayout implements  LayoutManager {
1598:                public void addLayoutComponent(String name, Component comp) {
1599:                    if (name.equals(CENTER))
1600:                        center = comp;
1601:                    else if (name.equals(LEFT))
1602:                        left = comp;
1603:                    else if (name.equals(RIGHT))
1604:                        right = comp;
1605:                    else if (name.equals(BOTTOM))
1606:                        bottom = comp;
1607:                    else if (name.equals(LEFT_OF_SCROLLBAR))
1608:                        leftOfScrollBar.addElement(comp);
1609:                }
1610:
1611:                public void removeLayoutComponent(Component comp) {
1612:                    if (center == comp)
1613:                        center = null;
1614:                    if (left == comp)
1615:                        left = null;
1616:                    if (right == comp)
1617:                        right = null;
1618:                    if (bottom == comp)
1619:                        bottom = null;
1620:                    else
1621:                        leftOfScrollBar.removeElement(comp);
1622:                }
1623:
1624:                public Dimension preferredLayoutSize(Container parent) {
1625:                    Dimension dim = new Dimension();
1626:                    Insets insets = getInsets();
1627:                    dim.width = insets.left + insets.right;
1628:                    dim.height = insets.top + insets.bottom;
1629:
1630:                    Dimension centerPref = center.getPreferredSize();
1631:                    dim.width += centerPref.width;
1632:                    dim.height += centerPref.height;
1633:
1634:                    Dimension leftPref = left.getPreferredSize();
1635:                    dim.width += leftPref.width;
1636:
1637:                    Dimension rightPref = right.getPreferredSize();
1638:                    dim.width += rightPref.width;
1639:
1640:                    Dimension bottomPref = bottom.getPreferredSize();
1641:                    dim.height += bottomPref.height;
1642:
1643:                    return dim;
1644:                }
1645:
1646:                public Dimension minimumLayoutSize(Container parent) {
1647:                    Dimension dim = new Dimension();
1648:                    Insets insets = getInsets();
1649:                    dim.width = insets.left + insets.right;
1650:                    dim.height = insets.top + insets.bottom;
1651:
1652:                    Dimension centerPref = center.getMinimumSize();
1653:                    dim.width += centerPref.width;
1654:                    dim.height += centerPref.height;
1655:
1656:                    Dimension leftPref = left.getMinimumSize();
1657:                    dim.width += leftPref.width;
1658:
1659:                    Dimension rightPref = right.getMinimumSize();
1660:                    dim.width += rightPref.width;
1661:
1662:                    Dimension bottomPref = bottom.getMinimumSize();
1663:                    dim.height += bottomPref.height;
1664:
1665:                    return dim;
1666:                }
1667:
1668:                public void layoutContainer(Container parent) {
1669:                    Dimension size = parent.getSize();
1670:                    Insets insets = parent.getInsets();
1671:                    int itop = insets.top;
1672:                    int ileft = insets.left;
1673:                    int ibottom = insets.bottom;
1674:                    int iright = insets.right;
1675:
1676:                    int leftWidth = left.getPreferredSize().width;
1677:                    int rightWidth = right.getPreferredSize().width;
1678:                    int bottomHeight = bottom.getPreferredSize().height;
1679:                    int centerWidth = size.width - leftWidth - rightWidth
1680:                            - ileft - iright;
1681:                    int centerHeight = size.height - bottomHeight - itop
1682:                            - ibottom;
1683:
1684:                    left.setBounds(ileft, itop, leftWidth, centerHeight);
1685:
1686:                    center.setBounds(leftWidth + ileft, itop, centerWidth,
1687:                            centerHeight);
1688:
1689:                    right.setBounds(ileft + leftWidth + centerWidth, itop,
1690:                            rightWidth, centerHeight);
1691:
1692:                    // Lay out all status components, in order
1693:                    Enumeration status = leftOfScrollBar.elements();
1694:                    while (status.hasMoreElements()) {
1695:                        Component comp = (Component) status.nextElement();
1696:                        Dimension dim = comp.getPreferredSize();
1697:                        comp.setBounds(ileft, itop + centerHeight, dim.width,
1698:                                bottomHeight);
1699:                        ileft += dim.width;
1700:                    }
1701:
1702:                    bottom.setBounds(ileft, itop + centerHeight, size.width
1703:                            - rightWidth - ileft - iright, bottomHeight);
1704:                }
1705:
1706:                // private members
1707:                private Component center;
1708:                private Component left;
1709:                private Component right;
1710:                private Component bottom;
1711:                private Vector leftOfScrollBar = new Vector();
1712:            }
1713:
1714:            static class CaretBlinker implements  ActionListener {
1715:                public void actionPerformed(ActionEvent evt) {
1716:                    if (focusedComponent != null && focusedComponent.hasFocus())
1717:                        focusedComponent.blinkCaret();
1718:                }
1719:            }
1720:
1721:            class MutableCaretEvent extends CaretEvent {
1722:                MutableCaretEvent() {
1723:                    super (JEditTextArea.this );
1724:                }
1725:
1726:                public int getDot() {
1727:                    return getCaretPosition();
1728:                }
1729:
1730:                public int getMark() {
1731:                    return getMarkPosition();
1732:                }
1733:            }
1734:
1735:            class AdjustHandler implements  AdjustmentListener {
1736:                public void adjustmentValueChanged(final AdjustmentEvent evt) {
1737:                    if (!scrollBarsInitialized)
1738:                        return;
1739:
1740:                    // If this is not done, mousePressed events accumilate
1741:                    // and the result is that scrolling doesn't stop after
1742:                    // the mouse is released
1743:                    SwingUtilities.invokeLater(new Runnable() {
1744:                        public void run() {
1745:                            if (evt.getAdjustable() == vertical)
1746:                                setFirstLine(vertical.getValue());
1747:                            else
1748:                                setHorizontalOffset(-horizontal.getValue());
1749:                        }
1750:                    });
1751:                }
1752:            }
1753:
1754:            class ComponentHandler extends ComponentAdapter {
1755:                public void componentResized(ComponentEvent evt) {
1756:                    recalculateVisibleLines();
1757:                    scrollBarsInitialized = true;
1758:                }
1759:            }
1760:
1761:            class DocumentHandler implements  DocumentListener {
1762:                public void insertUpdate(DocumentEvent evt) {
1763:                    documentChanged(evt);
1764:
1765:                    int offset = evt.getOffset();
1766:                    int length = evt.getLength();
1767:
1768:                    int newStart;
1769:                    int newEnd;
1770:
1771:                    if (selectionStart > offset
1772:                            || (selectionStart == selectionEnd && selectionStart == offset))
1773:                        newStart = selectionStart + length;
1774:                    else
1775:                        newStart = selectionStart;
1776:
1777:                    if (selectionEnd >= offset)
1778:                        newEnd = selectionEnd + length;
1779:                    else
1780:                        newEnd = selectionEnd;
1781:
1782:                    select(newStart, newEnd);
1783:                }
1784:
1785:                public void removeUpdate(DocumentEvent evt) {
1786:                    documentChanged(evt);
1787:
1788:                    int offset = evt.getOffset();
1789:                    int length = evt.getLength();
1790:
1791:                    int newStart;
1792:                    int newEnd;
1793:
1794:                    if (selectionStart > offset) {
1795:                        if (selectionStart > offset + length)
1796:                            newStart = selectionStart - length;
1797:                        else
1798:                            newStart = offset;
1799:                    } else
1800:                        newStart = selectionStart;
1801:
1802:                    if (selectionEnd > offset) {
1803:                        if (selectionEnd > offset + length)
1804:                            newEnd = selectionEnd - length;
1805:                        else
1806:                            newEnd = offset;
1807:                    } else
1808:                        newEnd = selectionEnd;
1809:
1810:                    select(newStart, newEnd);
1811:                }
1812:
1813:                public void changedUpdate(DocumentEvent evt) {
1814:                }
1815:            }
1816:
1817:            class DragHandler implements  MouseMotionListener {
1818:                public void mouseDragged(MouseEvent evt) {
1819:                    if (popup != null && popup.isVisible())
1820:                        return;
1821:
1822:                    setSelectionRectangular((evt.getModifiers() & InputEvent.CTRL_MASK) != 0);
1823:                    select(getMarkPosition(),
1824:                            xyToOffset(evt.getX(), evt.getY()));
1825:                }
1826:
1827:                public void mouseMoved(MouseEvent evt) {
1828:                }
1829:            }
1830:
1831:            class FocusHandler implements  FocusListener {
1832:                public void focusGained(FocusEvent evt) {
1833:                    setCaretVisible(true);
1834:                    focusedComponent = JEditTextArea.this ;
1835:                }
1836:
1837:                public void focusLost(FocusEvent evt) {
1838:                    setCaretVisible(false);
1839:                    focusedComponent = null;
1840:                }
1841:            }
1842:
1843:            class MouseHandler extends MouseAdapter {
1844:                public void mousePressed(MouseEvent evt) {
1845:                    requestFocus();
1846:
1847:                    // Focus events not fired sometimes?
1848:                    setCaretVisible(true);
1849:                    focusedComponent = JEditTextArea.this ;
1850:
1851:                    int line = yToLine(evt.getY());
1852:                    int offset = xToOffset(line, evt.getX());
1853:                    int dot = getLineStartOffset(line) + offset;
1854:
1855:                    if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0
1856:                            && popup != null) {
1857:                        doSingleClick(evt, line, offset, dot);
1858:                        popup.show(painter, evt.getX(), evt.getY());
1859:                        return;
1860:                    }
1861:
1862:                    switch (evt.getClickCount()) {
1863:                    case 1:
1864:                        doSingleClick(evt, line, offset, dot);
1865:                        break;
1866:                    case 2:
1867:
1868:                        // It uses the bracket matching stuff, so
1869:                        // it can throw a BLE
1870:                        try {
1871:                            doDoubleClick(evt, line, offset, dot);
1872:                        } catch (BadLocationException bl) {
1873:                            bl.printStackTrace();
1874:                        }
1875:                        break;
1876:                    case 3:
1877:                        doTripleClick(evt, line, offset, dot);
1878:                        break;
1879:                    }
1880:                }
1881:
1882:                private void doSingleClick(MouseEvent evt, int line,
1883:                        int offset, int dot) {
1884:                    if ((evt.getModifiers() & InputEvent.SHIFT_MASK) != 0) {
1885:                        rectSelect = (evt.getModifiers() & InputEvent.CTRL_MASK) != 0;
1886:                        select(getMarkPosition(), dot);
1887:                    } else
1888:                        setCaretPosition(dot);
1889:                }
1890:
1891:                private void doDoubleClick(MouseEvent evt, int line,
1892:                        int offset, int dot) throws BadLocationException {
1893:                    // Ignore empty lines
1894:                    if (getLineLength(line) == 0)
1895:                        return;
1896:
1897:                    try {
1898:                        int bracket = TextUtilities.findMatchingBracket(
1899:                                document, Math.max(0, dot - 1));
1900:                        if (bracket != -1) {
1901:                            int mark = getMarkPosition();
1902:                            // Hack
1903:                            if (bracket > mark) {
1904:                                bracket++;
1905:                                mark--;
1906:                            }
1907:                            select(mark, bracket);
1908:                            return;
1909:                        }
1910:                    } catch (BadLocationException bl) {
1911:                        bl.printStackTrace();
1912:                    }
1913:
1914:                    // Ok, it's not a bracket... select the word
1915:                    String lineText = getLineText(line);
1916:                    char ch = lineText.charAt(Math.max(0, offset - 1));
1917:
1918:                    String noWordSep = (String) document
1919:                            .getProperty("noWordSep");
1920:                    if (noWordSep == null)
1921:                        noWordSep = "";
1922:
1923:                    // If the user clicked on a non-letter char,
1924:                    // we select the surrounding non-letters
1925:                    boolean selectNoLetter = (!Character.isLetterOrDigit(ch) && noWordSep
1926:                            .indexOf(ch) == -1);
1927:
1928:                    int wordStart = 0;
1929:
1930:                    for (int i = offset - 1; i >= 0; i--) {
1931:                        ch = lineText.charAt(i);
1932:                        if (selectNoLetter
1933:                                ^ (!Character.isLetterOrDigit(ch) && noWordSep
1934:                                        .indexOf(ch) == -1)) {
1935:                            wordStart = i + 1;
1936:                            break;
1937:                        }
1938:                    }
1939:
1940:                    int wordEnd = lineText.length();
1941:                    for (int i = offset; i < lineText.length(); i++) {
1942:                        ch = lineText.charAt(i);
1943:                        if (selectNoLetter
1944:                                ^ (!Character.isLetterOrDigit(ch) && noWordSep
1945:                                        .indexOf(ch) == -1)) {
1946:                            wordEnd = i;
1947:                            break;
1948:                        }
1949:                    }
1950:
1951:                    int lineStart = getLineStartOffset(line);
1952:                    select(lineStart + wordStart, lineStart + wordEnd);
1953:
1954:                    /*
1955:                                             String lineText = getLineText(line);
1956:                                             String noWordSep = (String)document.getProperty("noWordSep");
1957:                                             int wordStart = TextUtilities.findWordStart(lineText,offset,noWordSep);
1958:                                             int wordEnd = TextUtilities.findWordEnd(lineText,offset,noWordSep);
1959:                                             int lineStart = getLineStartOffset(line);
1960:                                             select(lineStart + wordStart,lineStart + wordEnd);
1961:                     */
1962:                }
1963:
1964:                private void doTripleClick(MouseEvent evt, int line,
1965:                        int offset, int dot) {
1966:                    select(getLineStartOffset(line), getLineEndOffset(line) - 1);
1967:                }
1968:            }
1969:
1970:            class CaretUndo extends AbstractUndoableEdit {
1971:                private int start;
1972:                private int end;
1973:
1974:                CaretUndo(int start, int end) {
1975:                    this .start = start;
1976:                    this .end = end;
1977:                }
1978:
1979:                public boolean isSignificant() {
1980:                    return false;
1981:                }
1982:
1983:                public String getPresentationName() {
1984:                    return "caret move";
1985:                }
1986:
1987:                public void undo() throws CannotUndoException {
1988:                    super .undo();
1989:
1990:                    select(start, end);
1991:                }
1992:
1993:                public void redo() throws CannotRedoException {
1994:                    super .redo();
1995:
1996:                    select(start, end);
1997:                }
1998:
1999:                public boolean addEdit(UndoableEdit edit) {
2000:                    if (edit instanceof  CaretUndo) {
2001:                        CaretUndo cedit = (CaretUndo) edit;
2002:                        start = cedit.start;
2003:                        end = cedit.end;
2004:                        cedit.die();
2005:
2006:                        return true;
2007:                    } else
2008:                        return false;
2009:                }
2010:            }
2011:
2012:            static {
2013:                caretTimer = new Timer(500, new CaretBlinker());
2014:                caretTimer.setInitialDelay(500);
2015:                caretTimer.start();
2016:            }
2017:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.