Source Code Cross Referenced for JEditTextArea.java in  » Report » iReport-2.0.5 » org » syntax » jedit » 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 » Report » iReport 2.0.5 » org.syntax.jedit 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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