Source Code Cross Referenced for JEditBuffer.java in  » Swing-Library » jEdit » org » gjt » sp » jedit » buffer » 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 » Swing Library » jEdit » org.gjt.sp.jedit.buffer 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * JEditBuffer.java - jEdit buffer
0003:         * :tabSize=8:indentSize=8:noTabs=false:
0004:         * :folding=explicit:collapseFolds=1:
0005:         *
0006:         * Copyright (C) 1998, 2005 Slava Pestov
0007:         * Portions copyright (C) 1999, 2000 mike dillon
0008:         *
0009:         * This program is free software; you can redistribute it and/or
0010:         * modify it under the terms of the GNU General Public License
0011:         * as published by the Free Software Foundation; either version 2
0012:         * of the License, or any later version.
0013:         *
0014:         * This program is distributed in the hope that it will be useful,
0015:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
0016:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0017:         * GNU General Public License for more details.
0018:         *
0019:         * You should have received a copy of the GNU General Public License
0020:         * along with this program; if not, write to the Free Software
0021:         * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
0022:         */
0023:
0024:        package org.gjt.sp.jedit.buffer;
0025:
0026:        //{{{ Imports
0027:        import org.gjt.sp.jedit.Debug;
0028:        import org.gjt.sp.jedit.Mode;
0029:        import org.gjt.sp.jedit.TextUtilities;
0030:        import org.gjt.sp.jedit.indent.IndentAction;
0031:        import org.gjt.sp.jedit.indent.IndentRule;
0032:        import org.gjt.sp.jedit.syntax.*;
0033:        import org.gjt.sp.jedit.textarea.TextArea;
0034:        import org.gjt.sp.util.IntegerArray;
0035:        import org.gjt.sp.util.Log;
0036:        import org.gjt.sp.util.StandardUtilities;
0037:
0038:        import javax.swing.*;
0039:        import javax.swing.text.Position;
0040:        import javax.swing.text.Segment;
0041:        import java.awt.*;
0042:        import java.util.*;
0043:        import java.util.List;
0044:        import java.util.concurrent.locks.ReentrantReadWriteLock;
0045:        import java.util.regex.Pattern;
0046:
0047:        //}}}
0048:
0049:        /**
0050:         * A <code>JEditBuffer</code> represents the contents of an open text
0051:         * file as it is maintained in the computer's memory (as opposed to
0052:         * how it may be stored on a disk).<p>
0053:         *
0054:         * This class is partially thread-safe, however you must pay attention to two
0055:         * very important guidelines:
0056:         * <ul>
0057:         * <li>Changes to a buffer can only be made from the AWT thread.
0058:         * <li>When accessing the buffer from another thread, you must
0059:         * grab a read lock if you plan on performing more than one call, to ensure that
0060:         * the buffer contents are not changed by the AWT thread for the duration of the
0061:         * lock. Only methods whose descriptions specify thread safety can be invoked
0062:         * from other threads.
0063:         * </ul>
0064:         *
0065:         * @author Slava Pestov
0066:         * @version $Id: JEditBuffer.java 11001 2007-11-08 09:37:38Z kpouer $
0067:         *
0068:         * @since jEdit 4.3pre3
0069:         */
0070:        public class JEditBuffer {
0071:            /**
0072:             * Line separator property.
0073:             */
0074:            public static final String LINESEP = "lineSeparator";
0075:
0076:            /**
0077:             * Character encoding used when loading and saving.
0078:             * @since jEdit 3.2pre4
0079:             */
0080:            public static final String ENCODING = "encoding";
0081:
0082:            //{{{ JEditBuffer constructor
0083:            public JEditBuffer(Map props) {
0084:                bufferListeners = new Vector<Listener>();
0085:                lock = new ReentrantReadWriteLock();
0086:                contentMgr = new ContentManager();
0087:                lineMgr = new LineManager();
0088:                positionMgr = new PositionManager(this );
0089:                undoMgr = new UndoManager(this );
0090:                seg = new Segment();
0091:                integerArray = new IntegerArray();
0092:                propertyLock = new Object();
0093:                properties = new HashMap<Object, PropValue>();
0094:
0095:                //{{{ need to convert entries of 'props' to PropValue instances
0096:                Set<Map.Entry> set = props.entrySet();
0097:                for (Map.Entry entry : set) {
0098:                    properties.put(entry.getKey(), new PropValue(entry
0099:                            .getValue(), false));
0100:                } //}}}
0101:
0102:                // fill in defaults for these from system properties if the
0103:                // corresponding buffer.XXX properties not set
0104:                if (getProperty(ENCODING) == null)
0105:                    properties.put(ENCODING, new PropValue(System
0106:                            .getProperty("file.encoding"), false));
0107:                if (getProperty(LINESEP) == null)
0108:                    properties.put(LINESEP, new PropValue(System
0109:                            .getProperty("line.separator"), false));
0110:            } //}}}
0111:
0112:            //{{{ JEditBuffer constructor
0113:            public JEditBuffer() {
0114:                bufferListeners = new Vector<Listener>();
0115:                lock = new ReentrantReadWriteLock();
0116:                contentMgr = new ContentManager();
0117:                lineMgr = new LineManager();
0118:                positionMgr = new PositionManager(this );
0119:                undoMgr = new UndoManager(this );
0120:                seg = new Segment();
0121:                integerArray = new IntegerArray();
0122:                propertyLock = new Object();
0123:                properties = new HashMap<Object, PropValue>();
0124:
0125:                properties.put("wrap", new PropValue("none", false));
0126:                properties.put("folding", new PropValue("none", false));
0127:                TokenMarker tokenMarker = new TokenMarker();
0128:                tokenMarker.addRuleSet(new ParserRuleSet("text", "MAIN"));
0129:                setTokenMarker(tokenMarker);
0130:
0131:                loadText(null, null);
0132:                // corresponding buffer.XXX properties not set
0133:                if (getProperty(ENCODING) == null)
0134:                    properties.put(ENCODING, new PropValue(System
0135:                            .getProperty("file.encoding"), false));
0136:                if (getProperty(LINESEP) == null)
0137:                    properties.put(LINESEP, new PropValue(System
0138:                            .getProperty("line.separator"), false));
0139:
0140:                setFoldHandler(new DummyFoldHandler());
0141:            } //}}}
0142:
0143:            //{{{ Flags
0144:
0145:            //{{{ isDirty() method
0146:            /**
0147:             * Returns whether there have been unsaved changes to this buffer.
0148:             * This method is thread-safe.
0149:             */
0150:            public boolean isDirty() {
0151:                return dirty;
0152:            } //}}}
0153:
0154:            //{{{ isLoading() method
0155:            public boolean isLoading() {
0156:                return loading;
0157:            } //}}}
0158:
0159:            //{{{ setLoading() method
0160:            public void setLoading(boolean loading) {
0161:                this .loading = loading;
0162:            } //}}}
0163:
0164:            //{{{ isPerformingIO() method
0165:            /**
0166:             * Returns true if the buffer is currently performing I/O.
0167:             * This method is thread-safe.
0168:             * @since jEdit 2.7pre1
0169:             */
0170:            public boolean isPerformingIO() {
0171:                return isLoading() || io;
0172:            } //}}}
0173:
0174:            //{{{ setPerformingIO() method
0175:            /**
0176:             * Returns true if the buffer is currently performing I/O.
0177:             * This method is thread-safe.
0178:             * @since jEdit 2.7pre1
0179:             */
0180:            public void setPerformingIO(boolean io) {
0181:                this .io = io;
0182:            } //}}}
0183:
0184:            //{{{ isEditable() method
0185:            /**
0186:             * Returns true if this file is editable, false otherwise. A file may
0187:             * become uneditable if it is read only, or if I/O is in progress.
0188:             * This method is thread-safe.
0189:             * @since jEdit 2.7pre1
0190:             */
0191:            public boolean isEditable() {
0192:                return !(isReadOnly() || isPerformingIO());
0193:            } //}}}
0194:
0195:            //{{{ isReadOnly() method
0196:            /**
0197:             * Returns true if this file is read only, false otherwise.
0198:             * This method is thread-safe.
0199:             */
0200:            public boolean isReadOnly() {
0201:                return readOnly || readOnlyOverride;
0202:            } //}}}
0203:
0204:            //{{{ setReadOnly() method
0205:            /**
0206:             * Sets the read only flag.
0207:             * @param readOnly The read only flag
0208:             */
0209:            public void setReadOnly(boolean readOnly) {
0210:                readOnlyOverride = readOnly;
0211:            } //}}}
0212:
0213:            //{{{ setDirty() method
0214:            /**
0215:             * Sets the 'dirty' (changed since last save) flag of this buffer.
0216:             */
0217:            public void setDirty(boolean d) {
0218:                boolean editable = isEditable();
0219:
0220:                if (d) {
0221:                    if (editable)
0222:                        dirty = true;
0223:                } else {
0224:                    dirty = false;
0225:
0226:                    // fixes dirty flag not being reset on
0227:                    // save/insert/undo/redo/undo
0228:                    if (!isUndoInProgress()) {
0229:                        // this ensures that undo can clear the dirty flag properly
0230:                        // when all edits up to a save are undone
0231:                        undoMgr.resetClearDirty();
0232:                    }
0233:                }
0234:            } //}}}
0235:
0236:            //}}}
0237:
0238:            //{{{ Thread safety
0239:
0240:            //{{{ readLock() method
0241:            /**
0242:             * The buffer is guaranteed not to change between calls to
0243:             * {@link #readLock()} and {@link #readUnlock()}.
0244:             */
0245:            public void readLock() {
0246:                lock.readLock().lock();
0247:            } //}}}
0248:
0249:            //{{{ readUnlock() method
0250:            /**
0251:             * The buffer is guaranteed not to change between calls to
0252:             * {@link #readLock()} and {@link #readUnlock()}.
0253:             */
0254:            public void readUnlock() {
0255:                lock.readLock().unlock();
0256:            } //}}}
0257:
0258:            //{{{ writeLock() method
0259:            /**
0260:             * Attempting to obtain read lock will block between calls to
0261:             * {@link #writeLock()} and {@link #writeUnlock()}.
0262:             */
0263:            public void writeLock() {
0264:                lock.writeLock().lock();
0265:            } //}}}
0266:
0267:            //{{{ writeUnlock() method
0268:            /**
0269:             * Attempting to obtain read lock will block between calls to
0270:             * {@link #writeLock()} and {@link #writeUnlock()}.
0271:             */
0272:            public void writeUnlock() {
0273:                lock.writeLock().unlock();
0274:            } //}}}
0275:
0276:            //}}}
0277:
0278:            //{{{ Line offset methods
0279:
0280:            //{{{ getLength() method
0281:            /**
0282:             * Returns the number of characters in the buffer. This method is thread-safe.
0283:             */
0284:            public int getLength() {
0285:                // no need to lock since this just returns a value and that's it
0286:                return contentMgr.getLength();
0287:            } //}}}
0288:
0289:            //{{{ getLineCount() method
0290:            /**
0291:             * Returns the number of physical lines in the buffer.
0292:             * This method is thread-safe.
0293:             * @since jEdit 3.1pre1
0294:             */
0295:            public int getLineCount() {
0296:                // no need to lock since this just returns a value and that's it
0297:                return lineMgr.getLineCount();
0298:            } //}}}
0299:
0300:            //{{{ getLineOfOffset() method
0301:            /**
0302:             * Returns the line containing the specified offset.
0303:             * This method is thread-safe.
0304:             * @param offset The offset
0305:             * @since jEdit 4.0pre1
0306:             */
0307:            public int getLineOfOffset(int offset) {
0308:                try {
0309:                    readLock();
0310:
0311:                    if (offset < 0 || offset > getLength())
0312:                        throw new ArrayIndexOutOfBoundsException(offset);
0313:
0314:                    return lineMgr.getLineOfOffset(offset);
0315:                } finally {
0316:                    readUnlock();
0317:                }
0318:            } //}}}
0319:
0320:            //{{{ getLineStartOffset() method
0321:            /**
0322:             * Returns the start offset of the specified line.
0323:             * This method is thread-safe.
0324:             * @param line The line
0325:             * @return The start offset of the specified line
0326:             * @since jEdit 4.0pre1
0327:             */
0328:            public int getLineStartOffset(int line) {
0329:                try {
0330:                    readLock();
0331:
0332:                    if (line < 0 || line >= lineMgr.getLineCount())
0333:                        throw new ArrayIndexOutOfBoundsException(line);
0334:                    else if (line == 0)
0335:                        return 0;
0336:
0337:                    return lineMgr.getLineEndOffset(line - 1);
0338:                } finally {
0339:                    readUnlock();
0340:                }
0341:            } //}}}
0342:
0343:            //{{{ getLineEndOffset() method
0344:            /**
0345:             * Returns the end offset of the specified line.
0346:             * This method is thread-safe.
0347:             * @param line The line
0348:             * @return The end offset of the specified line
0349:             * invalid.
0350:             * @since jEdit 4.0pre1
0351:             */
0352:            public int getLineEndOffset(int line) {
0353:                try {
0354:                    readLock();
0355:
0356:                    if (line < 0 || line >= lineMgr.getLineCount())
0357:                        throw new ArrayIndexOutOfBoundsException(line);
0358:
0359:                    return lineMgr.getLineEndOffset(line);
0360:                } finally {
0361:                    readUnlock();
0362:                }
0363:            } //}}}
0364:
0365:            //{{{ getLineLength() method
0366:            /**
0367:             * Returns the length of the specified line.
0368:             * This method is thread-safe.
0369:             * @param line The line
0370:             * @since jEdit 4.0pre1
0371:             */
0372:            public int getLineLength(int line) {
0373:                try {
0374:                    readLock();
0375:
0376:                    return getLineEndOffset(line) - getLineStartOffset(line)
0377:                            - 1;
0378:                } finally {
0379:                    readUnlock();
0380:                }
0381:            } //}}}
0382:
0383:            //{{{ getPriorNonEmptyLine() method
0384:            /**
0385:             * Auto indent needs this.
0386:             */
0387:            public int getPriorNonEmptyLine(int lineIndex) {
0388:                int returnValue = -1;
0389:
0390:                if (!mode.getIgnoreWhitespace()) {
0391:                    return lineIndex - 1;
0392:                }
0393:
0394:                for (int i = lineIndex - 1; i >= 0; i--) {
0395:                    getLineText(i, seg);
0396:                    if (seg.count != 0)
0397:                        returnValue = i;
0398:                    for (int j = 0; j < seg.count; j++) {
0399:                        char ch = seg.array[seg.offset + j];
0400:                        if (!Character.isWhitespace(ch))
0401:                            return i;
0402:                    }
0403:                }
0404:
0405:                // didn't find a line that contains non-whitespace chars
0406:                // so return index of prior whitespace line
0407:                return returnValue;
0408:            } //}}}
0409:
0410:            //}}}
0411:
0412:            //{{{ Text getters and setters
0413:
0414:            //{{{ getLineText() method
0415:            /**
0416:             * Returns the text on the specified line.
0417:             * This method is thread-safe.
0418:             * @param line The line
0419:             * @return The text, or null if the line is invalid
0420:             * @since jEdit 4.0pre1
0421:             */
0422:            public String getLineText(int line) {
0423:                if (line < 0 || line >= lineMgr.getLineCount())
0424:                    throw new ArrayIndexOutOfBoundsException(line);
0425:
0426:                try {
0427:                    readLock();
0428:
0429:                    int start = line == 0 ? 0 : lineMgr
0430:                            .getLineEndOffset(line - 1);
0431:                    int end = lineMgr.getLineEndOffset(line);
0432:
0433:                    return getText(start, end - start - 1);
0434:                } finally {
0435:                    readUnlock();
0436:                }
0437:            } //}}}
0438:
0439:            //{{{ getLineText() method
0440:            /**
0441:             * Returns the specified line in a <code>Segment</code>.<p>
0442:             *
0443:             * Using a <classname>Segment</classname> is generally more
0444:             * efficient than using a <classname>String</classname> because it
0445:             * results in less memory allocation and array copying.<p>
0446:             *
0447:             * This method is thread-safe.
0448:             *
0449:             * @param line The line
0450:             * @since jEdit 4.0pre1
0451:             */
0452:            public void getLineText(int line, Segment segment) {
0453:                if (line < 0 || line >= lineMgr.getLineCount())
0454:                    throw new ArrayIndexOutOfBoundsException(line);
0455:
0456:                try {
0457:                    readLock();
0458:
0459:                    int start = line == 0 ? 0 : lineMgr
0460:                            .getLineEndOffset(line - 1);
0461:                    int end = lineMgr.getLineEndOffset(line);
0462:
0463:                    getText(start, end - start - 1, segment);
0464:                } finally {
0465:                    readUnlock();
0466:                }
0467:            } //}}}
0468:
0469:            //{{{ getText() method
0470:            /**
0471:             * Returns the specified text range. This method is thread-safe.
0472:             * @param start The start offset
0473:             * @param length The number of characters to get
0474:             */
0475:            public String getText(int start, int length) {
0476:                try {
0477:                    readLock();
0478:
0479:                    if (start < 0 || length < 0
0480:                            || start + length > contentMgr.getLength())
0481:                        throw new ArrayIndexOutOfBoundsException(start + ":"
0482:                                + length);
0483:
0484:                    return contentMgr.getText(start, length);
0485:                } finally {
0486:                    readUnlock();
0487:                }
0488:            } //}}}
0489:
0490:            //{{{ getText() method
0491:            /**
0492:             * Returns the specified text range in a <code>Segment</code>.<p>
0493:             *
0494:             * Using a <classname>Segment</classname> is generally more
0495:             * efficient than using a <classname>String</classname> because it
0496:             * results in less memory allocation and array copying.<p>
0497:             *
0498:             * This method is thread-safe.
0499:             *
0500:             * @param start The start offset
0501:             * @param length The number of characters to get
0502:             * @param seg The segment to copy the text to
0503:             */
0504:            public void getText(int start, int length, Segment seg) {
0505:                try {
0506:                    readLock();
0507:
0508:                    if (start < 0 || length < 0
0509:                            || start + length > contentMgr.getLength())
0510:                        throw new ArrayIndexOutOfBoundsException(start + ":"
0511:                                + length);
0512:
0513:                    contentMgr.getText(start, length, seg);
0514:                } finally {
0515:                    readUnlock();
0516:                }
0517:            } //}}}
0518:
0519:            //{{{ insert() method
0520:            /**
0521:             * Inserts a string into the buffer.
0522:             * @param offset The offset
0523:             * @param str The string
0524:             * @since jEdit 4.0pre1
0525:             */
0526:            public void insert(int offset, String str) {
0527:                if (str == null)
0528:                    return;
0529:
0530:                int len = str.length();
0531:
0532:                if (len == 0)
0533:                    return;
0534:
0535:                if (isReadOnly())
0536:                    throw new RuntimeException("buffer read-only");
0537:
0538:                try {
0539:                    writeLock();
0540:
0541:                    if (offset < 0 || offset > contentMgr.getLength())
0542:                        throw new ArrayIndexOutOfBoundsException(offset);
0543:
0544:                    contentMgr.insert(offset, str);
0545:
0546:                    integerArray.clear();
0547:
0548:                    for (int i = 0; i < len; i++) {
0549:                        if (str.charAt(i) == '\n')
0550:                            integerArray.add(i + 1);
0551:                    }
0552:
0553:                    if (!undoInProgress) {
0554:                        undoMgr.contentInserted(offset, len, str, !dirty);
0555:                    }
0556:
0557:                    contentInserted(offset, len, integerArray);
0558:                } finally {
0559:                    writeUnlock();
0560:                }
0561:            } //}}}
0562:
0563:            //{{{ insert() method
0564:            /**
0565:             * Inserts a string into the buffer.
0566:             * @param offset The offset
0567:             * @param seg The segment
0568:             * @since jEdit 4.0pre1
0569:             */
0570:            public void insert(int offset, Segment seg) {
0571:                if (seg.count == 0)
0572:                    return;
0573:
0574:                if (isReadOnly())
0575:                    throw new RuntimeException("buffer read-only");
0576:
0577:                try {
0578:                    writeLock();
0579:
0580:                    if (offset < 0 || offset > contentMgr.getLength())
0581:                        throw new ArrayIndexOutOfBoundsException(offset);
0582:
0583:                    contentMgr.insert(offset, seg);
0584:
0585:                    integerArray.clear();
0586:
0587:                    for (int i = 0; i < seg.count; i++) {
0588:                        if (seg.array[seg.offset + i] == '\n')
0589:                            integerArray.add(i + 1);
0590:                    }
0591:
0592:                    if (!undoInProgress) {
0593:                        undoMgr.contentInserted(offset, seg.count, seg
0594:                                .toString(), !dirty);
0595:                    }
0596:
0597:                    contentInserted(offset, seg.count, integerArray);
0598:                } finally {
0599:                    writeUnlock();
0600:                }
0601:            } //}}}
0602:
0603:            //{{{ remove() method
0604:            /**
0605:             * Removes the specified rang efrom the buffer.
0606:             * @param offset The start offset
0607:             * @param length The number of characters to remove
0608:             */
0609:            public void remove(int offset, int length) {
0610:                if (length == 0)
0611:                    return;
0612:
0613:                if (isReadOnly())
0614:                    throw new RuntimeException("buffer read-only");
0615:
0616:                try {
0617:                    transaction = true;
0618:
0619:                    writeLock();
0620:
0621:                    if (offset < 0 || length < 0
0622:                            || offset + length > contentMgr.getLength())
0623:                        throw new ArrayIndexOutOfBoundsException(offset + ":"
0624:                                + length);
0625:
0626:                    int startLine = lineMgr.getLineOfOffset(offset);
0627:                    int endLine = lineMgr.getLineOfOffset(offset + length);
0628:
0629:                    int numLines = endLine - startLine;
0630:
0631:                    if (!undoInProgress && !loading) {
0632:                        undoMgr.contentRemoved(offset, length, getText(offset,
0633:                                length), !dirty);
0634:                    }
0635:
0636:                    firePreContentRemoved(startLine, offset, numLines, length);
0637:
0638:                    contentMgr.remove(offset, length);
0639:                    lineMgr.contentRemoved(startLine, offset, numLines, length);
0640:                    positionMgr.contentRemoved(offset, length);
0641:
0642:                    fireContentRemoved(startLine, offset, numLines, length);
0643:
0644:                    /* otherwise it will be delivered later */
0645:                    if (!undoInProgress && !insideCompoundEdit())
0646:                        fireTransactionComplete();
0647:
0648:                    setDirty(true);
0649:                } finally {
0650:                    transaction = false;
0651:
0652:                    writeUnlock();
0653:                }
0654:            } //}}}
0655:
0656:            //}}}
0657:
0658:            //{{{ Indentation
0659:
0660:            //{{{ removeTrailingWhiteSpace() method
0661:            /**
0662:             * Removes trailing whitespace from all lines in the specified list.
0663:             * @param lines The line numbers
0664:             * @since jEdit 3.2pre1
0665:             */
0666:            public void removeTrailingWhiteSpace(int[] lines) {
0667:                try {
0668:                    beginCompoundEdit();
0669:
0670:                    for (int i = 0; i < lines.length; i++) {
0671:                        int pos, lineStart, lineEnd, tail;
0672:
0673:                        getLineText(lines[i], seg);
0674:
0675:                        // blank line
0676:                        if (seg.count == 0)
0677:                            continue;
0678:
0679:                        lineStart = seg.offset;
0680:                        lineEnd = seg.offset + seg.count - 1;
0681:
0682:                        for (pos = lineEnd; pos >= lineStart; pos--) {
0683:                            if (!Character.isWhitespace(seg.array[pos]))
0684:                                break;
0685:                        }
0686:
0687:                        tail = lineEnd - pos;
0688:
0689:                        // no whitespace
0690:                        if (tail == 0)
0691:                            continue;
0692:
0693:                        remove(getLineEndOffset(lines[i]) - 1 - tail, tail);
0694:                    }
0695:                } finally {
0696:                    endCompoundEdit();
0697:                }
0698:            } //}}}
0699:
0700:            //{{{ shiftIndentLeft() method
0701:            /**
0702:             * Shifts the indent of each line in the specified list to the left.
0703:             * @param lines The line numbers
0704:             * @since jEdit 3.2pre1
0705:             */
0706:            public void shiftIndentLeft(int[] lines) {
0707:                int tabSize = getTabSize();
0708:                int indentSize = getIndentSize();
0709:                boolean noTabs = getBooleanProperty("noTabs");
0710:
0711:                try {
0712:                    beginCompoundEdit();
0713:
0714:                    for (int i = 0; i < lines.length; i++) {
0715:                        int lineStart = getLineStartOffset(lines[i]);
0716:                        String line = getLineText(lines[i]);
0717:                        int whiteSpace = StandardUtilities
0718:                                .getLeadingWhiteSpace(line);
0719:                        if (whiteSpace == 0)
0720:                            continue;
0721:                        int whiteSpaceWidth = Math.max(0, StandardUtilities
0722:                                .getLeadingWhiteSpaceWidth(line, tabSize)
0723:                                - indentSize);
0724:
0725:                        insert(lineStart + whiteSpace, StandardUtilities
0726:                                .createWhiteSpace(whiteSpaceWidth, noTabs ? 0
0727:                                        : tabSize));
0728:                        remove(lineStart, whiteSpace);
0729:                    }
0730:
0731:                } finally {
0732:                    endCompoundEdit();
0733:                }
0734:            } //}}}
0735:
0736:            //{{{ shiftIndentRight() method
0737:            /**
0738:             * Shifts the indent of each line in the specified list to the right.
0739:             * @param lines The line numbers
0740:             * @since jEdit 3.2pre1
0741:             */
0742:            public void shiftIndentRight(int[] lines) {
0743:                try {
0744:                    beginCompoundEdit();
0745:
0746:                    int tabSize = getTabSize();
0747:                    int indentSize = getIndentSize();
0748:                    boolean noTabs = getBooleanProperty("noTabs");
0749:                    for (int i = 0; i < lines.length; i++) {
0750:                        int lineStart = getLineStartOffset(lines[i]);
0751:                        String line = getLineText(lines[i]);
0752:                        int whiteSpace = StandardUtilities
0753:                                .getLeadingWhiteSpace(line);
0754:
0755:                        // silly usability hack
0756:                        //if(lines.length != 1 && whiteSpace == 0)
0757:                        //	continue;
0758:
0759:                        int whiteSpaceWidth = StandardUtilities
0760:                                .getLeadingWhiteSpaceWidth(line, tabSize)
0761:                                + indentSize;
0762:                        insert(lineStart + whiteSpace, StandardUtilities
0763:                                .createWhiteSpace(whiteSpaceWidth, noTabs ? 0
0764:                                        : tabSize));
0765:                        remove(lineStart, whiteSpace);
0766:                    }
0767:                } finally {
0768:                    endCompoundEdit();
0769:                }
0770:            } //}}}
0771:
0772:            //{{{ indentLines() method
0773:            /**
0774:             * Indents all specified lines.
0775:             * @param start The first line to indent
0776:             * @param end The last line to indent
0777:             * @since jEdit 3.1pre3
0778:             */
0779:            public void indentLines(int start, int end) {
0780:                try {
0781:                    beginCompoundEdit();
0782:                    for (int i = start; i <= end; i++)
0783:                        indentLine(i, true);
0784:                } finally {
0785:                    endCompoundEdit();
0786:                }
0787:            } //}}}
0788:
0789:            //{{{ indentLines() method
0790:            /**
0791:             * Indents all specified lines.
0792:             * @param lines The line numbers
0793:             * @since jEdit 3.2pre1
0794:             */
0795:            public void indentLines(int[] lines) {
0796:                try {
0797:                    beginCompoundEdit();
0798:                    for (int i = 0; i < lines.length; i++)
0799:                        indentLine(lines[i], true);
0800:                } finally {
0801:                    endCompoundEdit();
0802:                }
0803:            } //}}}
0804:
0805:            //{{{ indentLine() method
0806:            /**
0807:             * @deprecated Use {@link #indentLine(int,boolean)} instead.
0808:             */
0809:            public boolean indentLine(int lineIndex, boolean canIncreaseIndent,
0810:                    boolean canDecreaseIndent) {
0811:                return indentLine(lineIndex, canDecreaseIndent);
0812:            } //}}}
0813:
0814:            //{{{ indentLine() method
0815:            /**
0816:             * Indents the specified line.
0817:             * @param lineIndex The line number to indent
0818:             * @param canDecreaseIndent If true, the indent can be decreased as a
0819:             * result of this. Set this to false for Tab key.
0820:             * @return true If indentation took place, false otherwise.
0821:             * @since jEdit 4.2pre2
0822:             */
0823:            public boolean indentLine(int lineIndex, boolean canDecreaseIndent) {
0824:                int[] whitespaceChars = new int[1];
0825:                int currentIndent = getCurrentIndentForLine(lineIndex,
0826:                        whitespaceChars);
0827:                int idealIndent = getIdealIndentForLine(lineIndex);
0828:
0829:                if (idealIndent == -1 || idealIndent == currentIndent
0830:                        || (!canDecreaseIndent && idealIndent < currentIndent))
0831:                    return false;
0832:
0833:                // Do it
0834:                try {
0835:                    beginCompoundEdit();
0836:
0837:                    int start = getLineStartOffset(lineIndex);
0838:
0839:                    remove(start, whitespaceChars[0]);
0840:                    insert(start, StandardUtilities.createWhiteSpace(
0841:                            idealIndent, getBooleanProperty("noTabs") ? 0
0842:                                    : getTabSize()));
0843:                } finally {
0844:                    endCompoundEdit();
0845:                }
0846:
0847:                return true;
0848:            } //}}}
0849:
0850:            //{{{ getCurrentIndentForLine() method
0851:            /**
0852:             * Returns the line's current leading indent.
0853:             * @param lineIndex The line number
0854:             * @param whitespaceChars If this is non-null, the number of whitespace
0855:             * characters is stored at the 0 index
0856:             * @since jEdit 4.2pre2
0857:             */
0858:            public int getCurrentIndentForLine(int lineIndex,
0859:                    int[] whitespaceChars) {
0860:                getLineText(lineIndex, seg);
0861:
0862:                int tabSize = getTabSize();
0863:
0864:                int currentIndent = 0;
0865:                loop: for (int i = 0; i < seg.count; i++) {
0866:                    char c = seg.array[seg.offset + i];
0867:                    switch (c) {
0868:                    case ' ':
0869:                        currentIndent++;
0870:                        if (whitespaceChars != null)
0871:                            whitespaceChars[0]++;
0872:                        break;
0873:                    case '\t':
0874:                        currentIndent += tabSize - (currentIndent % tabSize);
0875:                        if (whitespaceChars != null)
0876:                            whitespaceChars[0]++;
0877:                        break;
0878:                    default:
0879:                        break loop;
0880:                    }
0881:                }
0882:
0883:                return currentIndent;
0884:            } //}}}
0885:
0886:            //{{{ getIdealIndentForLine() method
0887:            /**
0888:             * Returns the ideal leading indent for the specified line.
0889:             * This will apply the various auto-indent rules.
0890:             * @param lineIndex The line number
0891:             */
0892:            public int getIdealIndentForLine(int lineIndex) {
0893:                int prevLineIndex = getPriorNonEmptyLine(lineIndex);
0894:                int prevPrevLineIndex = prevLineIndex < 0 ? -1
0895:                        : getPriorNonEmptyLine(prevLineIndex);
0896:
0897:                int oldIndent = prevLineIndex == -1 ? 0 : StandardUtilities
0898:                        .getLeadingWhiteSpaceWidth(getLineText(prevLineIndex),
0899:                                getTabSize());
0900:                int newIndent = oldIndent;
0901:
0902:                List<IndentRule> indentRules = getIndentRules(lineIndex);
0903:                List<IndentAction> actions = new LinkedList<IndentAction>();
0904:                for (int i = 0; i < indentRules.size(); i++) {
0905:                    IndentRule rule = indentRules.get(i);
0906:                    rule.apply(this , lineIndex, prevLineIndex,
0907:                            prevPrevLineIndex, actions);
0908:                }
0909:
0910:                for (IndentAction action : actions) {
0911:                    newIndent = action.calculateIndent(this , lineIndex,
0912:                            oldIndent, newIndent);
0913:                    if (!action.keepChecking())
0914:                        break;
0915:                }
0916:                if (newIndent < 0)
0917:                    newIndent = 0;
0918:
0919:                return newIndent;
0920:            } //}}}
0921:
0922:            //{{{ getVirtualWidth() method
0923:            /**
0924:             * Returns the virtual column number (taking tabs into account) of the
0925:             * specified position.
0926:             *
0927:             * @param line The line number
0928:             * @param column The column number
0929:             * @since jEdit 4.1pre1
0930:             */
0931:            public int getVirtualWidth(int line, int column) {
0932:                try {
0933:                    readLock();
0934:
0935:                    int start = getLineStartOffset(line);
0936:                    getText(start, column, seg);
0937:
0938:                    return StandardUtilities.getVirtualWidth(seg, getTabSize());
0939:                } finally {
0940:                    readUnlock();
0941:                }
0942:            } //}}}
0943:
0944:            //{{{ getOffsetOfVirtualColumn() method
0945:            /**
0946:             * Returns the offset of a virtual column number (taking tabs
0947:             * into account) relative to the start of the line in question.
0948:             *
0949:             * @param line The line number
0950:             * @param column The virtual column number
0951:             * @param totalVirtualWidth If this array is non-null, the total
0952:             * virtual width will be stored in its first location if this method
0953:             * returns -1.
0954:             *
0955:             * @return -1 if the column is out of bounds
0956:             *
0957:             * @since jEdit 4.1pre1
0958:             */
0959:            public int getOffsetOfVirtualColumn(int line, int column,
0960:                    int[] totalVirtualWidth) {
0961:                try {
0962:                    readLock();
0963:
0964:                    getLineText(line, seg);
0965:
0966:                    return StandardUtilities.getOffsetOfVirtualColumn(seg,
0967:                            getTabSize(), column, totalVirtualWidth);
0968:                } finally {
0969:                    readUnlock();
0970:                }
0971:            } //}}}
0972:
0973:            //{{{ insertAtColumn() method
0974:            /**
0975:             * Like the {@link #insert(int,String)} method, but inserts the string at
0976:             * the specified virtual column. Inserts spaces as appropriate if
0977:             * the line is shorter than the column.
0978:             * @param line The line number
0979:             * @param col The virtual column number
0980:             * @param str The string
0981:             */
0982:            public void insertAtColumn(int line, int col, String str) {
0983:                try {
0984:                    writeLock();
0985:
0986:                    int[] total = new int[1];
0987:                    int offset = getOffsetOfVirtualColumn(line, col, total);
0988:                    if (offset == -1) {
0989:                        offset = getLineEndOffset(line) - 1;
0990:                        str = StandardUtilities.createWhiteSpace(
0991:                                col - total[0], 0)
0992:                                + str;
0993:                    } else
0994:                        offset += getLineStartOffset(line);
0995:
0996:                    insert(offset, str);
0997:                } finally {
0998:                    writeUnlock();
0999:                }
1000:            } //}}}
1001:
1002:            //{{{ insertIndented() method
1003:            /**
1004:             * Inserts a string into the buffer, indenting each line of the string
1005:             * to match the indent of the first line.
1006:             *
1007:             * @param offset The offset
1008:             * @param text The text
1009:             *
1010:             * @return The number of characters of indent inserted on each new
1011:             * line. This is used by the abbreviations code.
1012:             *
1013:             * @since jEdit 4.2pre14
1014:             */
1015:            public int insertIndented(int offset, String text) {
1016:                try {
1017:                    beginCompoundEdit();
1018:
1019:                    // obtain the leading indent for later use
1020:                    int firstLine = getLineOfOffset(offset);
1021:                    String lineText = getLineText(firstLine);
1022:                    int leadingIndent = StandardUtilities
1023:                            .getLeadingWhiteSpaceWidth(lineText, getTabSize());
1024:
1025:                    String whiteSpace = StandardUtilities.createWhiteSpace(
1026:                            leadingIndent, getBooleanProperty("noTabs") ? 0
1027:                                    : getTabSize());
1028:
1029:                    insert(offset, text);
1030:
1031:                    int lastLine = getLineOfOffset(offset + text.length());
1032:
1033:                    // note that if firstLine == lastLine, loop does not
1034:                    // execute
1035:                    for (int i = firstLine + 1; i <= lastLine; i++) {
1036:                        insert(getLineStartOffset(i), whiteSpace);
1037:                    }
1038:
1039:                    return whiteSpace.length();
1040:                } finally {
1041:                    endCompoundEdit();
1042:                }
1043:            } //}}}
1044:
1045:            //{{{ isElectricKey() method
1046:            /**
1047:             * Should inserting this character trigger a re-indent of
1048:             * the current line?
1049:             * @since jEdit 4.3pre2
1050:             * @deprecated Use #isElectricKey(char,int)
1051:             */
1052:            public boolean isElectricKey(char ch) {
1053:                return mode.isElectricKey(ch);
1054:            } //}}}
1055:
1056:            //{{{ isElectricKey() method
1057:            /**
1058:             * Should inserting this character trigger a re-indent of
1059:             * the current line?
1060:             * @since jEdit 4.3pre9
1061:             */
1062:            public boolean isElectricKey(char ch, int line) {
1063:                TokenMarker.LineContext ctx = lineMgr.getLineContext(line);
1064:                Mode mode = ModeProvider.instance.getMode(ctx.rules
1065:                        .getModeName());
1066:
1067:                // mode can be null, though that's probably an error "further up":
1068:                if (mode == null)
1069:                    return false;
1070:                return mode.isElectricKey(ch);
1071:            } //}}}
1072:
1073:            //}}}
1074:
1075:            //{{{ Syntax highlighting
1076:
1077:            //{{{ markTokens() method
1078:            /**
1079:             * Returns the syntax tokens for the specified line.
1080:             * @param lineIndex The line number
1081:             * @param tokenHandler The token handler that will receive the syntax
1082:             * tokens
1083:             * @since jEdit 4.1pre1
1084:             */
1085:            public void markTokens(int lineIndex, TokenHandler tokenHandler) {
1086:                Segment seg;
1087:                if (SwingUtilities.isEventDispatchThread())
1088:                    seg = this .seg;
1089:                else
1090:                    seg = new Segment();
1091:
1092:                if (lineIndex < 0 || lineIndex >= lineMgr.getLineCount())
1093:                    throw new ArrayIndexOutOfBoundsException(lineIndex);
1094:
1095:                int firstInvalidLineContext = lineMgr
1096:                        .getFirstInvalidLineContext();
1097:                int start;
1098:                if (textMode || firstInvalidLineContext == -1) {
1099:                    start = lineIndex;
1100:                } else {
1101:                    start = Math.min(firstInvalidLineContext, lineIndex);
1102:                }
1103:
1104:                if (Debug.TOKEN_MARKER_DEBUG)
1105:                    Log.log(Log.DEBUG, this , "tokenize from " + start + " to "
1106:                            + lineIndex);
1107:                TokenMarker.LineContext oldContext = null;
1108:                TokenMarker.LineContext context = null;
1109:                for (int i = start; i <= lineIndex; i++) {
1110:                    getLineText(i, seg);
1111:
1112:                    oldContext = lineMgr.getLineContext(i);
1113:
1114:                    TokenMarker.LineContext prevContext = ((i == 0 || textMode) ? null
1115:                            : lineMgr.getLineContext(i - 1));
1116:
1117:                    context = tokenMarker.markTokens(prevContext,
1118:                            (i == lineIndex ? tokenHandler
1119:                                    : DummyTokenHandler.INSTANCE), seg);
1120:                    lineMgr.setLineContext(i, context);
1121:                }
1122:
1123:                int lineCount = lineMgr.getLineCount();
1124:                if (lineCount - 1 == lineIndex)
1125:                    lineMgr.setFirstInvalidLineContext(-1);
1126:                else if (oldContext != context)
1127:                    lineMgr.setFirstInvalidLineContext(lineIndex + 1);
1128:                else if (firstInvalidLineContext == -1)
1129:                    /* do nothing */;
1130:                else {
1131:                    lineMgr.setFirstInvalidLineContext(Math.max(
1132:                            firstInvalidLineContext, lineIndex + 1));
1133:                }
1134:            } //}}}
1135:
1136:            //{{{ getTokenMarker() method
1137:            public TokenMarker getTokenMarker() {
1138:                return tokenMarker;
1139:            } //}}}
1140:
1141:            //{{{ setTokenMarker() method
1142:            public void setTokenMarker(TokenMarker tokenMarker) {
1143:                TokenMarker oldTokenMarker = this .tokenMarker;
1144:
1145:                this .tokenMarker = tokenMarker;
1146:
1147:                // don't do this on initial token marker
1148:                if (oldTokenMarker != null && tokenMarker != oldTokenMarker) {
1149:                    lineMgr.setFirstInvalidLineContext(0);
1150:                }
1151:            } //}}}
1152:
1153:            //{{{ createPosition() method
1154:            /**
1155:             * Creates a floating position.
1156:             * @param offset The offset
1157:             */
1158:            public Position createPosition(int offset) {
1159:                try {
1160:                    readLock();
1161:
1162:                    if (offset < 0 || offset > contentMgr.getLength())
1163:                        throw new ArrayIndexOutOfBoundsException(offset);
1164:
1165:                    return positionMgr.createPosition(offset);
1166:                } finally {
1167:                    readUnlock();
1168:                }
1169:            } //}}}
1170:
1171:            //}}}
1172:
1173:            //{{{ Property methods
1174:
1175:            //{{{ propertiesChanged() method
1176:            /**
1177:             * Reloads settings from the properties. This should be called
1178:             * after the <code>syntax</code> or <code>folding</code>
1179:             * buffer-local properties are changed.
1180:             */
1181:            public void propertiesChanged() {
1182:                String folding = getStringProperty("folding");
1183:                FoldHandler handler = FoldHandler.getFoldHandler(folding);
1184:
1185:                if (handler != null) {
1186:                    setFoldHandler(handler);
1187:                } else {
1188:                    if (folding != null)
1189:                        Log.log(Log.WARNING, this ,
1190:                                "invalid 'folding' property: " + folding);
1191:                    setFoldHandler(new DummyFoldHandler());
1192:                }
1193:            } //}}}
1194:
1195:            //{{{ getTabSize() method
1196:            /**
1197:             * Returns the tab size used in this buffer. This is equivalent
1198:             * to calling <code>getProperty("tabSize")</code>.
1199:             * This method is thread-safe.
1200:             */
1201:            public int getTabSize() {
1202:                int tabSize = getIntegerProperty("tabSize", 8);
1203:                if (tabSize <= 0)
1204:                    return 8;
1205:                else
1206:                    return tabSize;
1207:            } //}}}
1208:
1209:            //{{{ getIndentSize() method
1210:            /**
1211:             * Returns the indent size used in this buffer. This is equivalent
1212:             * to calling <code>getProperty("indentSize")</code>.
1213:             * This method is thread-safe.
1214:             * @since jEdit 2.7pre1
1215:             */
1216:            public int getIndentSize() {
1217:                int indentSize = getIntegerProperty("indentSize", 8);
1218:                if (indentSize <= 0)
1219:                    return 8;
1220:                else
1221:                    return indentSize;
1222:            } //}}}
1223:
1224:            //{{{ getProperty() method
1225:            /**
1226:             * Returns the value of a buffer-local property.<p>
1227:             *
1228:             * Using this method is generally discouraged, because it returns an
1229:             * <code>Object</code> which must be cast to another type
1230:             * in order to be useful, and this can cause problems if the object
1231:             * is of a different type than what the caller expects.<p>
1232:             *
1233:             * The following methods should be used instead:
1234:             * <ul>
1235:             * <li>{@link #getStringProperty(String)}</li>
1236:             * <li>{@link #getBooleanProperty(String)}</li>
1237:             * <li>{@link #getIntegerProperty(String,int)}</li>
1238:             * </ul>
1239:             *
1240:             * This method is thread-safe.
1241:             *
1242:             * @param name The property name. For backwards compatibility, this
1243:             * is an <code>Object</code>, not a <code>String</code>.
1244:             */
1245:            public Object getProperty(Object name) {
1246:                synchronized (propertyLock) {
1247:                    // First try the buffer-local properties
1248:                    PropValue o = properties.get(name);
1249:                    if (o != null)
1250:                        return o.value;
1251:
1252:                    // For backwards compatibility
1253:                    if (!(name instanceof  String))
1254:                        return null;
1255:
1256:                    Object retVal = getDefaultProperty((String) name);
1257:
1258:                    if (retVal == null)
1259:                        return null;
1260:                    else {
1261:                        properties.put(name, new PropValue(retVal, true));
1262:                        return retVal;
1263:                    }
1264:                }
1265:            } //}}}
1266:
1267:            //{{{ getDefaultProperty() method
1268:            public Object getDefaultProperty(String key) {
1269:                return null;
1270:            } //}}}
1271:
1272:            //{{{ setProperty() method
1273:            /**
1274:             * Sets the value of a buffer-local property.
1275:             * @param name The property name
1276:             * @param value The property value
1277:             * @since jEdit 4.0pre1
1278:             */
1279:            public void setProperty(String name, Object value) {
1280:                if (value == null)
1281:                    properties.remove(name);
1282:                else {
1283:                    PropValue test = properties.get(name);
1284:                    if (test == null)
1285:                        properties.put(name, new PropValue(value, false));
1286:                    else if (test.value.equals(value)) {
1287:                        // do nothing
1288:                    } else {
1289:                        test.value = value;
1290:                        test.defaultValue = false;
1291:                    }
1292:                }
1293:            } //}}}
1294:
1295:            //{{{ setDefaultProperty() method
1296:            public void setDefaultProperty(String name, Object value) {
1297:                properties.put(name, new PropValue(value, true));
1298:            } //}}}
1299:
1300:            //{{{ unsetProperty() method
1301:            /**
1302:             * Clears the value of a buffer-local property.
1303:             * @param name The property name
1304:             * @since jEdit 4.0pre1
1305:             */
1306:            public void unsetProperty(String name) {
1307:                properties.remove(name);
1308:            } //}}}
1309:
1310:            //{{{ resetCachedProperties() method
1311:            public void resetCachedProperties() {
1312:                // Need to reset properties that were cached defaults,
1313:                // since the defaults might have changed.
1314:                Iterator<PropValue> iter = properties.values().iterator();
1315:                while (iter.hasNext()) {
1316:                    PropValue value = iter.next();
1317:                    if (value.defaultValue)
1318:                        iter.remove();
1319:                }
1320:            } //}}}
1321:
1322:            //{{{ getStringProperty() method
1323:            /**
1324:             * Returns the value of a string property. This method is thread-safe.
1325:             * @param name The property name
1326:             * @since jEdit 4.0pre1
1327:             */
1328:            public String getStringProperty(String name) {
1329:                Object obj = getProperty(name);
1330:                if (obj != null)
1331:                    return obj.toString();
1332:                else
1333:                    return null;
1334:            } //}}}
1335:
1336:            //{{{ setStringProperty() method
1337:            /**
1338:             * Sets a string property.
1339:             * @param name The property name
1340:             * @param value The value
1341:             * @since jEdit 4.0pre1
1342:             */
1343:            public void setStringProperty(String name, String value) {
1344:                setProperty(name, value);
1345:            } //}}}
1346:
1347:            //{{{ getBooleanProperty() method
1348:            /**
1349:             * Returns the value of a boolean property. This method is thread-safe.
1350:             * @param name The property name
1351:             * @since jEdit 4.0pre1
1352:             */
1353:            public boolean getBooleanProperty(String name) {
1354:                Object obj = getProperty(name);
1355:                if (obj instanceof  Boolean)
1356:                    return (Boolean) obj;
1357:                else if ("true".equals(obj) || "on".equals(obj)
1358:                        || "yes".equals(obj))
1359:                    return true;
1360:                else
1361:                    return false;
1362:            } //}}}
1363:
1364:            //{{{ setBooleanProperty() method
1365:            /**
1366:             * Sets a boolean property.
1367:             * @param name The property name
1368:             * @param value The value
1369:             * @since jEdit 4.0pre1
1370:             */
1371:            public void setBooleanProperty(String name, boolean value) {
1372:                setProperty(name, value ? Boolean.TRUE : Boolean.FALSE);
1373:            } //}}}
1374:
1375:            //{{{ getIntegerProperty() method
1376:            /**
1377:             * Returns the value of an integer property. This method is thread-safe.
1378:             * @param name The property name
1379:             * @since jEdit 4.0pre1
1380:             */
1381:            public int getIntegerProperty(String name, int defaultValue) {
1382:                boolean defaultValueFlag;
1383:                Object obj;
1384:                PropValue value = properties.get(name);
1385:                if (value != null) {
1386:                    obj = value.value;
1387:                    defaultValueFlag = value.defaultValue;
1388:                } else {
1389:                    obj = getProperty(name);
1390:                    // will be cached from now on...
1391:                    defaultValueFlag = true;
1392:                }
1393:
1394:                if (obj == null)
1395:                    return defaultValue;
1396:                else if (obj instanceof  Number)
1397:                    return ((Number) obj).intValue();
1398:                else {
1399:                    try {
1400:                        int returnValue = Integer.parseInt(obj.toString()
1401:                                .trim());
1402:                        properties.put(name, new PropValue(returnValue,
1403:                                defaultValueFlag));
1404:                        return returnValue;
1405:                    } catch (Exception e) {
1406:                        return defaultValue;
1407:                    }
1408:                }
1409:            } //}}}
1410:
1411:            //{{{ setIntegerProperty() method
1412:            /**
1413:             * Sets an integer property.
1414:             * @param name The property name
1415:             * @param value The value
1416:             * @since jEdit 4.0pre1
1417:             */
1418:            public void setIntegerProperty(String name, int value) {
1419:                setProperty(name, value);
1420:            } //}}}
1421:
1422:            //{{{ getPatternProperty()
1423:            /**
1424:             * Returns the value of a property as a regular expression.
1425:             * This method is thread-safe.
1426:             * @param name The property name
1427:             * @param flags Regular expression compilation flags
1428:             * @since jEdit 4.3pre5
1429:             */
1430:            public Pattern getPatternProperty(String name, int flags) {
1431:                synchronized (propertyLock) {
1432:                    boolean defaultValueFlag;
1433:                    Object obj;
1434:                    PropValue value = properties.get(name);
1435:                    if (value != null) {
1436:                        obj = value.value;
1437:                        defaultValueFlag = value.defaultValue;
1438:                    } else {
1439:                        obj = getProperty(name);
1440:                        // will be cached from now on...
1441:                        defaultValueFlag = true;
1442:                    }
1443:
1444:                    if (obj == null)
1445:                        return null;
1446:                    else if (obj instanceof  Pattern)
1447:                        return (Pattern) obj;
1448:                    else {
1449:                        Pattern re = Pattern.compile(obj.toString(), flags);
1450:                        properties.put(name,
1451:                                new PropValue(re, defaultValueFlag));
1452:                        return re;
1453:                    }
1454:                }
1455:            } //}}}
1456:
1457:            //{{{ getRuleSetAtOffset() method
1458:            /**
1459:             * Returns the syntax highlighting ruleset at the specified offset.
1460:             * @since jEdit 4.1pre1
1461:             */
1462:            public ParserRuleSet getRuleSetAtOffset(int offset) {
1463:                int line = getLineOfOffset(offset);
1464:                offset -= getLineStartOffset(line);
1465:                if (offset != 0)
1466:                    offset--;
1467:
1468:                DefaultTokenHandler tokens = new DefaultTokenHandler();
1469:                markTokens(line, tokens);
1470:                Token token = TextUtilities.getTokenAtOffset(
1471:                        tokens.getTokens(), offset);
1472:                return token.rules;
1473:            } //}}}
1474:
1475:            //{{{ getKeywordMapAtOffset() method
1476:            /**
1477:             * Returns the syntax highlighting keyword map in effect at the
1478:             * specified offset. Used by the <b>Complete Word</b> command to
1479:             * complete keywords.
1480:             * @param offset The offset
1481:             * @since jEdit 4.0pre3
1482:             */
1483:            public KeywordMap getKeywordMapAtOffset(int offset) {
1484:                return getRuleSetAtOffset(offset).getKeywords();
1485:            } //}}}
1486:
1487:            //{{{ getContextSensitiveProperty() method
1488:            /**
1489:             * Some settings, like comment start and end strings, can
1490:             * vary between different parts of a buffer (HTML text and inline
1491:             * JavaScript, for example).
1492:             * @param offset The offset
1493:             * @param name The property name
1494:             * @since jEdit 4.0pre3
1495:             */
1496:            public String getContextSensitiveProperty(int offset, String name) {
1497:                ParserRuleSet rules = getRuleSetAtOffset(offset);
1498:
1499:                Object value = null;
1500:
1501:                Map<String, String> rulesetProps = rules.getProperties();
1502:                if (rulesetProps != null)
1503:                    value = rulesetProps.get(name);
1504:
1505:                if (value == null)
1506:                    return null;
1507:                else
1508:                    return String.valueOf(value);
1509:            } //}}}
1510:
1511:            //{{{ getMode() method
1512:            /**
1513:             * Returns this buffer's edit mode. This method is thread-safe.
1514:             */
1515:            public Mode getMode() {
1516:                return mode;
1517:            } //}}}
1518:
1519:            //{{{ setMode() method
1520:            /**
1521:             * Sets this buffer's edit mode. Note that calling this before a buffer
1522:             * is loaded will have no effect; in that case, set the "mode" property
1523:             * to the name of the mode. A bit inelegant, I know...
1524:             * @param mode The mode name
1525:             * @since jEdit 4.2pre1
1526:             */
1527:            public void setMode(String mode) {
1528:                setMode(ModeProvider.instance.getMode(mode));
1529:            } //}}}
1530:
1531:            //{{{ setMode() method
1532:            /**
1533:             * Sets this buffer's edit mode. Note that calling this before a buffer
1534:             * is loaded will have no effect; in that case, set the "mode" property
1535:             * to the name of the mode. A bit inelegant, I know...
1536:             * @param mode The mode
1537:             */
1538:            public void setMode(Mode mode) {
1539:                /* This protects against stupid people (like me)
1540:                 * doing stuff like buffer.setMode(jEdit.getMode(...)); */
1541:                if (mode == null)
1542:                    throw new NullPointerException("Mode must be non-null");
1543:
1544:                this .mode = mode;
1545:
1546:                textMode = "text".equals(mode.getName());
1547:
1548:                setTokenMarker(mode.getTokenMarker());
1549:
1550:                resetCachedProperties();
1551:                propertiesChanged();
1552:            } //}}}
1553:
1554:            //}}}
1555:
1556:            //{{{ Folding methods
1557:
1558:            //{{{ isFoldStart() method
1559:            /**
1560:             * Returns if the specified line begins a fold.
1561:             * @since jEdit 3.1pre1
1562:             */
1563:            public boolean isFoldStart(int line) {
1564:                return line != getLineCount() - 1
1565:                        && getFoldLevel(line) < getFoldLevel(line + 1);
1566:            } //}}}
1567:
1568:            //{{{ isFoldEnd() method
1569:            /**
1570:             * Returns if the specified line ends a fold.
1571:             * @since jEdit 4.2pre5
1572:             */
1573:            public boolean isFoldEnd(int line) {
1574:                return line != getLineCount() - 1
1575:                        && getFoldLevel(line) > getFoldLevel(line + 1);
1576:            } //}}}
1577:
1578:            //{{{ invalidateCachedFoldLevels() method
1579:            /**
1580:             * Invalidates all cached fold level information.
1581:             * @since jEdit 4.1pre11
1582:             */
1583:            public void invalidateCachedFoldLevels() {
1584:                lineMgr.setFirstInvalidFoldLevel(0);
1585:                fireFoldLevelChanged(0, getLineCount());
1586:            } //}}}
1587:
1588:            //{{{ getFoldLevel() method
1589:            /**
1590:             * Returns the fold level of the specified line.
1591:             * @param line A physical line index
1592:             * @since jEdit 3.1pre1
1593:             */
1594:            public int getFoldLevel(int line) {
1595:                if (line < 0 || line >= lineMgr.getLineCount())
1596:                    throw new ArrayIndexOutOfBoundsException(line);
1597:
1598:                if (foldHandler instanceof  DummyFoldHandler)
1599:                    return 0;
1600:
1601:                int firstInvalidFoldLevel = lineMgr.getFirstInvalidFoldLevel();
1602:                if (firstInvalidFoldLevel == -1 || line < firstInvalidFoldLevel) {
1603:                    return lineMgr.getFoldLevel(line);
1604:                } else {
1605:                    if (Debug.FOLD_DEBUG)
1606:                        Log.log(Log.DEBUG, this , "Invalid fold levels from "
1607:                                + firstInvalidFoldLevel + " to " + line);
1608:
1609:                    int newFoldLevel = 0;
1610:                    boolean changed = false;
1611:
1612:                    for (int i = firstInvalidFoldLevel; i <= line; i++) {
1613:                        newFoldLevel = foldHandler.getFoldLevel(this , i, seg);
1614:                        if (newFoldLevel != lineMgr.getFoldLevel(i)) {
1615:                            if (Debug.FOLD_DEBUG)
1616:                                Log.log(Log.DEBUG, this , i
1617:                                        + " fold level changed");
1618:                            changed = true;
1619:                        }
1620:                        lineMgr.setFoldLevel(i, newFoldLevel);
1621:                    }
1622:
1623:                    if (line == lineMgr.getLineCount() - 1)
1624:                        lineMgr.setFirstInvalidFoldLevel(-1);
1625:                    else
1626:                        lineMgr.setFirstInvalidFoldLevel(line + 1);
1627:
1628:                    if (changed) {
1629:                        if (Debug.FOLD_DEBUG)
1630:                            Log.log(Log.DEBUG, this , "fold level changed: "
1631:                                    + firstInvalidFoldLevel + ',' + line);
1632:                        fireFoldLevelChanged(firstInvalidFoldLevel, line);
1633:                    }
1634:
1635:                    return newFoldLevel;
1636:                }
1637:            } //}}}
1638:
1639:            //{{{ getFoldAtLine() method
1640:            /**
1641:             * Returns an array. The first element is the start line, the
1642:             * second element is the end line, of the fold containing the
1643:             * specified line number.
1644:             * @param line The line number
1645:             * @since jEdit 4.0pre3
1646:             */
1647:            public int[] getFoldAtLine(int line) {
1648:                int start, end;
1649:
1650:                if (isFoldStart(line)) {
1651:                    start = line;
1652:                    int foldLevel = getFoldLevel(line);
1653:
1654:                    line++;
1655:
1656:                    while (getFoldLevel(line) > foldLevel) {
1657:                        line++;
1658:
1659:                        if (line == getLineCount())
1660:                            break;
1661:                    }
1662:
1663:                    end = line - 1;
1664:                } else {
1665:                    start = line;
1666:                    int foldLevel = getFoldLevel(line);
1667:                    while (getFoldLevel(start) >= foldLevel) {
1668:                        if (start == 0)
1669:                            break;
1670:                        else
1671:                            start--;
1672:                    }
1673:
1674:                    end = line;
1675:                    while (getFoldLevel(end) >= foldLevel) {
1676:                        end++;
1677:
1678:                        if (end == getLineCount())
1679:                            break;
1680:                    }
1681:
1682:                    end--;
1683:                }
1684:
1685:                while (getLineLength(end) == 0 && end > start)
1686:                    end--;
1687:
1688:                return new int[] { start, end };
1689:            } //}}}
1690:
1691:            //{{{ getFoldHandler() method
1692:            /**
1693:             * Returns the current buffer's fold handler.
1694:             * @since jEdit 4.2pre1
1695:             */
1696:            public FoldHandler getFoldHandler() {
1697:                return foldHandler;
1698:            } //}}}
1699:
1700:            //{{{ setFoldHandler() method
1701:            /**
1702:             * Sets the buffer's fold handler.
1703:             * @since jEdit 4.2pre2
1704:             */
1705:            public void setFoldHandler(FoldHandler foldHandler) {
1706:                FoldHandler oldFoldHandler = this .foldHandler;
1707:
1708:                if (foldHandler.equals(oldFoldHandler))
1709:                    return;
1710:
1711:                this .foldHandler = foldHandler;
1712:
1713:                lineMgr.setFirstInvalidFoldLevel(0);
1714:
1715:                fireFoldHandlerChanged();
1716:            } //}}}
1717:
1718:            //}}}
1719:
1720:            //{{{ Undo
1721:
1722:            //{{{ undo() method
1723:            /**
1724:             * Undoes the most recent edit.
1725:             *
1726:             * @since jEdit 4.0pre1
1727:             */
1728:            public void undo(TextArea textArea) {
1729:                if (undoMgr == null)
1730:                    return;
1731:
1732:                if (!isEditable()) {
1733:                    textArea.getToolkit().beep();
1734:                    return;
1735:                }
1736:
1737:                try {
1738:                    writeLock();
1739:
1740:                    undoInProgress = true;
1741:                    int caret = undoMgr.undo();
1742:
1743:                    if (caret == -1)
1744:                        textArea.getToolkit().beep();
1745:                    else
1746:                        textArea.setCaretPosition(caret);
1747:
1748:                    fireTransactionComplete();
1749:                } finally {
1750:                    undoInProgress = false;
1751:
1752:                    writeUnlock();
1753:                }
1754:            } //}}}
1755:
1756:            //{{{ redo() method
1757:            /**
1758:             * Redoes the most recently undone edit.
1759:             *
1760:             * @since jEdit 2.7pre2
1761:             */
1762:            public void redo(TextArea textArea) {
1763:                if (undoMgr == null)
1764:                    return;
1765:
1766:                if (!isEditable()) {
1767:                    Toolkit.getDefaultToolkit().beep();
1768:                    return;
1769:                }
1770:
1771:                try {
1772:                    writeLock();
1773:
1774:                    undoInProgress = true;
1775:                    int caret = undoMgr.redo();
1776:                    if (caret == -1)
1777:                        textArea.getToolkit().beep();
1778:                    else
1779:                        textArea.setCaretPosition(caret);
1780:
1781:                    fireTransactionComplete();
1782:                } finally {
1783:                    undoInProgress = false;
1784:
1785:                    writeUnlock();
1786:                }
1787:            } //}}}
1788:
1789:            //{{{ isTransactionInProgress() method
1790:            /**
1791:             * Returns if an undo or compound edit is currently in progress. If this
1792:             * method returns true, then eventually a
1793:             * {@link org.gjt.sp.jedit.buffer.BufferListener#transactionComplete(JEditBuffer)}
1794:             * buffer event will get fired.
1795:             * @since jEdit 4.0pre6
1796:             */
1797:            public boolean isTransactionInProgress() {
1798:                return transaction || undoInProgress || insideCompoundEdit();
1799:            } //}}}
1800:
1801:            //{{{ beginCompoundEdit() method
1802:            /**
1803:             * Starts a compound edit. All edits from now on until
1804:             * {@link #endCompoundEdit()} are called will be merged
1805:             * into one. This can be used to make a complex operation
1806:             * undoable in one step. Nested calls to
1807:             * {@link #beginCompoundEdit()} behave as expected,
1808:             * requiring the same number of {@link #endCompoundEdit()}
1809:             * calls to end the edit.
1810:             * @see #endCompoundEdit()
1811:             */
1812:            public void beginCompoundEdit() {
1813:                try {
1814:                    writeLock();
1815:
1816:                    undoMgr.beginCompoundEdit();
1817:                } finally {
1818:                    writeUnlock();
1819:                }
1820:            } //}}}
1821:
1822:            //{{{ endCompoundEdit() method
1823:            /**
1824:             * Ends a compound edit. All edits performed since
1825:             * {@link #beginCompoundEdit()} was called can now
1826:             * be undone in one step by calling {@link #undo(TextArea)}.
1827:             * @see #beginCompoundEdit()
1828:             */
1829:            public void endCompoundEdit() {
1830:                try {
1831:                    writeLock();
1832:
1833:                    undoMgr.endCompoundEdit();
1834:
1835:                    if (!insideCompoundEdit())
1836:                        fireTransactionComplete();
1837:                } finally {
1838:                    writeUnlock();
1839:                }
1840:            }//}}}
1841:
1842:            //{{{ insideCompoundEdit() method
1843:            /**
1844:             * Returns if a compound edit is currently active.
1845:             * @since jEdit 3.1pre1
1846:             */
1847:            public boolean insideCompoundEdit() {
1848:                return undoMgr.insideCompoundEdit();
1849:            } //}}}
1850:
1851:            //{{{ isUndoInProgress() method
1852:            /**
1853:             * Returns if an undo or redo is currently being performed.
1854:             * @since jEdit 4.3pre3
1855:             */
1856:            public boolean isUndoInProgress() {
1857:                return undoInProgress;
1858:            } //}}}
1859:
1860:            //}}}
1861:
1862:            //{{{ Buffer events
1863:            public static final int NORMAL_PRIORITY = 0;
1864:            public static final int HIGH_PRIORITY = 1;
1865:
1866:            static class Listener {
1867:                BufferListener listener;
1868:                int priority;
1869:
1870:                Listener(BufferListener listener, int priority) {
1871:                    this .listener = listener;
1872:                    this .priority = priority;
1873:                }
1874:            }
1875:
1876:            //{{{ addBufferListener() method
1877:            /**
1878:             * Adds a buffer change listener.
1879:             * @param listener The listener
1880:             * @param priority Listeners with HIGH_PRIORITY get the event before
1881:             * listeners with NORMAL_PRIORITY
1882:             * @since jEdit 4.3pre3
1883:             */
1884:            public void addBufferListener(BufferListener listener, int priority) {
1885:                Listener l = new Listener(listener, priority);
1886:                for (int i = 0; i < bufferListeners.size(); i++) {
1887:                    Listener _l = bufferListeners.get(i);
1888:                    if (_l.priority < priority) {
1889:                        bufferListeners.add(i, l);
1890:                        return;
1891:                    }
1892:                }
1893:                bufferListeners.add(l);
1894:            } //}}}
1895:
1896:            //{{{ addBufferListener() method
1897:            /**
1898:             * Adds a buffer change listener.
1899:             * @param listener The listener
1900:             * @since jEdit 4.3pre3
1901:             */
1902:            public void addBufferListener(BufferListener listener) {
1903:                addBufferListener(listener, NORMAL_PRIORITY);
1904:            } //}}}
1905:
1906:            //{{{ removeBufferListener() method
1907:            /**
1908:             * Removes a buffer change listener.
1909:             * @param listener The listener
1910:             * @since jEdit 4.3pre3
1911:             */
1912:            public void removeBufferListener(BufferListener listener) {
1913:                for (int i = 0; i < bufferListeners.size(); i++) {
1914:                    if (bufferListeners.get(i).listener == listener) {
1915:                        bufferListeners.remove(i);
1916:                        return;
1917:                    }
1918:                }
1919:            } //}}}
1920:
1921:            //{{{ getBufferListeners() method
1922:            /**
1923:             * Returns an array of registered buffer change listeners.
1924:             * @since jEdit 4.3pre3
1925:             */
1926:            public BufferListener[] getBufferListeners() {
1927:                BufferListener[] returnValue = new BufferListener[bufferListeners
1928:                        .size()];
1929:                for (int i = 0; i < returnValue.length; i++) {
1930:                    returnValue[i] = bufferListeners.get(i).listener;
1931:                }
1932:                return returnValue;
1933:            } //}}}
1934:
1935:            //}}}
1936:
1937:            //{{{ Protected members
1938:
1939:            protected Mode mode;
1940:            protected Segment seg;
1941:            protected boolean textMode;
1942:            protected UndoManager undoMgr;
1943:
1944:            //{{{ Event firing methods
1945:
1946:            //{{{ fireFoldLevelChanged() method
1947:            protected void fireFoldLevelChanged(int start, int end) {
1948:                for (int i = 0; i < bufferListeners.size(); i++) {
1949:                    BufferListener listener = getListener(i);
1950:                    try {
1951:                        listener.foldLevelChanged(this , start, end);
1952:                    } catch (Throwable t) {
1953:                        Log.log(Log.ERROR, this ,
1954:                                "Exception while sending buffer event to "
1955:                                        + listener + " :");
1956:                        Log.log(Log.ERROR, this , t);
1957:                    }
1958:                }
1959:            } //}}}
1960:
1961:            //{{{ fireContentInserted() method
1962:            protected void fireContentInserted(int startLine, int offset,
1963:                    int numLines, int length) {
1964:                for (int i = 0; i < bufferListeners.size(); i++) {
1965:                    BufferListener listener = getListener(i);
1966:                    try {
1967:                        listener.contentInserted(this , startLine, offset,
1968:                                numLines, length);
1969:                    } catch (Throwable t) {
1970:                        Log.log(Log.ERROR, this ,
1971:                                "Exception while sending buffer event to "
1972:                                        + listener + " :");
1973:                        Log.log(Log.ERROR, this , t);
1974:                    }
1975:                }
1976:            } //}}}
1977:
1978:            //{{{ fireContentRemoved() method
1979:            protected void fireContentRemoved(int startLine, int offset,
1980:                    int numLines, int length) {
1981:                for (int i = 0; i < bufferListeners.size(); i++) {
1982:                    BufferListener listener = getListener(i);
1983:                    try {
1984:                        listener.contentRemoved(this , startLine, offset,
1985:                                numLines, length);
1986:                    } catch (Throwable t) {
1987:                        Log.log(Log.ERROR, this ,
1988:                                "Exception while sending buffer event to "
1989:                                        + listener + " :");
1990:                        Log.log(Log.ERROR, this , t);
1991:                    }
1992:                }
1993:            } //}}}
1994:
1995:            //{{{ fireContentInserted() method
1996:            protected void firePreContentInserted(int startLine, int offset,
1997:                    int numLines, int length) {
1998:                for (int i = 0; i < bufferListeners.size(); i++) {
1999:                    BufferListener listener = getListener(i);
2000:                    try {
2001:                        listener.preContentInserted(this , startLine, offset,
2002:                                numLines, length);
2003:                    } catch (Throwable t) {
2004:                        Log.log(Log.ERROR, this ,
2005:                                "Exception while sending buffer event to "
2006:                                        + listener + " :");
2007:                        Log.log(Log.ERROR, this , t);
2008:                    }
2009:                }
2010:            } //}}}
2011:
2012:            //{{{ firePreContentRemoved() method
2013:            protected void firePreContentRemoved(int startLine, int offset,
2014:                    int numLines, int length) {
2015:                for (int i = 0; i < bufferListeners.size(); i++) {
2016:                    BufferListener listener = getListener(i);
2017:                    try {
2018:                        listener.preContentRemoved(this , startLine, offset,
2019:                                numLines, length);
2020:                    } catch (Throwable t) {
2021:                        Log.log(Log.ERROR, this ,
2022:                                "Exception while sending buffer event to "
2023:                                        + listener + " :");
2024:                        Log.log(Log.ERROR, this , t);
2025:                    }
2026:                }
2027:            } //}}}
2028:
2029:            //{{{ fireTransactionComplete() method
2030:            protected void fireTransactionComplete() {
2031:                for (int i = 0; i < bufferListeners.size(); i++) {
2032:                    BufferListener listener = getListener(i);
2033:                    try {
2034:                        listener.transactionComplete(this );
2035:                    } catch (Throwable t) {
2036:                        Log.log(Log.ERROR, this ,
2037:                                "Exception while sending buffer event to "
2038:                                        + listener + " :");
2039:                        Log.log(Log.ERROR, this , t);
2040:                    }
2041:                }
2042:            } //}}}
2043:
2044:            //{{{ fireFoldHandlerChanged() method
2045:            protected void fireFoldHandlerChanged() {
2046:                for (int i = 0; i < bufferListeners.size(); i++) {
2047:                    BufferListener listener = getListener(i);
2048:                    try {
2049:                        listener.foldHandlerChanged(this );
2050:                    } catch (Throwable t) {
2051:                        Log.log(Log.ERROR, this ,
2052:                                "Exception while sending buffer event to "
2053:                                        + listener + " :");
2054:                        Log.log(Log.ERROR, this , t);
2055:                    }
2056:                }
2057:            } //}}}
2058:
2059:            //{{{ fireBufferLoaded() method
2060:            protected void fireBufferLoaded() {
2061:                for (int i = 0; i < bufferListeners.size(); i++) {
2062:                    BufferListener listener = getListener(i);
2063:                    try {
2064:                        listener.bufferLoaded(this );
2065:                    } catch (Throwable t) {
2066:                        Log.log(Log.ERROR, this ,
2067:                                "Exception while sending buffer event to "
2068:                                        + listener + " :");
2069:                        Log.log(Log.ERROR, this , t);
2070:                    }
2071:                }
2072:            } //}}}
2073:
2074:            //}}}
2075:
2076:            //{{{ isFileReadOnly() method
2077:            protected boolean isFileReadOnly() {
2078:                return readOnly;
2079:            } //}}}
2080:
2081:            //{{{ setFileReadOnly() method
2082:            protected void setFileReadOnly(boolean readOnly) {
2083:                this .readOnly = readOnly;
2084:            } //}}}
2085:
2086:            //{{{ loadText() method
2087:            protected void loadText(Segment seg, IntegerArray endOffsets) {
2088:                if (seg == null)
2089:                    seg = new Segment(new char[1024], 0, 0);
2090:
2091:                if (endOffsets == null) {
2092:                    endOffsets = new IntegerArray();
2093:                    endOffsets.add(1);
2094:                }
2095:
2096:                try {
2097:                    writeLock();
2098:
2099:                    // For `reload' command
2100:                    // contentMgr.remove() changes this!
2101:                    int length = getLength();
2102:
2103:                    firePreContentRemoved(0, 0, getLineCount() - 1, length);
2104:
2105:                    contentMgr.remove(0, length);
2106:                    lineMgr.contentRemoved(0, 0, getLineCount() - 1, length);
2107:                    positionMgr.contentRemoved(0, length);
2108:                    fireContentRemoved(0, 0, getLineCount() - 1, length);
2109:
2110:                    firePreContentInserted(0, 0, endOffsets.getSize() - 1,
2111:                            seg.count - 1);
2112:                    // theoretically a segment could
2113:                    // have seg.offset != 0 but
2114:                    // SegmentBuffer never does that
2115:                    contentMgr._setContent(seg.array, seg.count);
2116:
2117:                    lineMgr._contentInserted(endOffsets);
2118:                    positionMgr.contentInserted(0, seg.count);
2119:
2120:                    fireContentInserted(0, 0, endOffsets.getSize() - 1,
2121:                            seg.count - 1);
2122:                } finally {
2123:                    writeUnlock();
2124:                }
2125:            } //}}}
2126:
2127:            //{{{ invalidateFoldLevels() method
2128:            protected void invalidateFoldLevels() {
2129:                lineMgr.setFirstInvalidFoldLevel(0);
2130:            } //}}}
2131:
2132:            //{{{ parseBufferLocalProperties() method
2133:            protected void parseBufferLocalProperties() {
2134:                int lastLine = Math.min(9, getLineCount() - 1);
2135:                parseBufferLocalProperties(getText(0,
2136:                        getLineEndOffset(lastLine) - 1));
2137:
2138:                // first line for last 10 lines, make sure not to overlap
2139:                // with the first 10
2140:                int firstLine = Math.max(lastLine + 1, getLineCount() - 10);
2141:                if (firstLine < getLineCount()) {
2142:                    int length = getLineEndOffset(getLineCount() - 1)
2143:                            - (getLineStartOffset(firstLine) + 1);
2144:                    parseBufferLocalProperties(getText(
2145:                            getLineStartOffset(firstLine), length));
2146:                }
2147:            } //}}}
2148:
2149:            //{{{ Used to store property values
2150:            protected static class PropValue {
2151:                PropValue(Object value, boolean defaultValue) {
2152:                    if (value == null)
2153:                        throw new NullPointerException();
2154:                    this .value = value;
2155:                    this .defaultValue = defaultValue;
2156:                }
2157:
2158:                Object value;
2159:
2160:                /**
2161:                 * If this is true, then this value is cached from the mode
2162:                 * or global defaults, so when the defaults change this property
2163:                 * value must be reset.
2164:                 */
2165:                boolean defaultValue;
2166:
2167:                /**
2168:                 * For debugging purposes.
2169:                 */
2170:                public String toString() {
2171:                    return value.toString();
2172:                }
2173:            } //}}}
2174:
2175:            //}}}
2176:
2177:            //{{{ Private members
2178:            private List<Listener> bufferListeners;
2179:            private final ReentrantReadWriteLock lock;
2180:            private ContentManager contentMgr;
2181:            private LineManager lineMgr;
2182:            private PositionManager positionMgr;
2183:            private FoldHandler foldHandler;
2184:            private IntegerArray integerArray;
2185:            private TokenMarker tokenMarker;
2186:            private boolean undoInProgress;
2187:            private boolean dirty;
2188:            private boolean readOnly;
2189:            private boolean readOnlyOverride;
2190:            private boolean transaction;
2191:            private boolean loading;
2192:            private boolean io;
2193:            private final Map<Object, PropValue> properties;
2194:            private final Object propertyLock;
2195:
2196:            //{{{ getListener() method
2197:            private BufferListener getListener(int index) {
2198:                return bufferListeners.get(index).listener;
2199:            } //}}}
2200:
2201:            //{{{ contentInserted() method
2202:            private void contentInserted(int offset, int length,
2203:                    IntegerArray endOffsets) {
2204:                try {
2205:                    transaction = true;
2206:
2207:                    int startLine = lineMgr.getLineOfOffset(offset);
2208:                    int numLines = endOffsets.getSize();
2209:
2210:                    if (!loading) {
2211:                        firePreContentInserted(startLine, offset, numLines,
2212:                                length);
2213:                    }
2214:
2215:                    lineMgr.contentInserted(startLine, offset, numLines,
2216:                            length, endOffsets);
2217:                    positionMgr.contentInserted(offset, length);
2218:
2219:                    setDirty(true);
2220:
2221:                    if (!loading) {
2222:                        fireContentInserted(startLine, offset, numLines, length);
2223:
2224:                        if (!undoInProgress && !insideCompoundEdit())
2225:                            fireTransactionComplete();
2226:                    }
2227:
2228:                } finally {
2229:                    transaction = false;
2230:                }
2231:            } //}}}
2232:
2233:            //{{{ parseBufferLocalProperties() method
2234:            private void parseBufferLocalProperties(String prop) {
2235:                StringBuilder buf = new StringBuilder();
2236:                String name = null;
2237:                boolean escape = false;
2238:                for (int i = 0; i < prop.length(); i++) {
2239:                    char c = prop.charAt(i);
2240:                    switch (c) {
2241:                    case ':':
2242:                        if (escape) {
2243:                            escape = false;
2244:                            buf.append(':');
2245:                            break;
2246:                        }
2247:                        if (name != null) {
2248:                            // use the low-level property setting code
2249:                            // so that if we have a buffer-local
2250:                            // property with the same value as a default,
2251:                            // later changes in the default don't affect
2252:                            // the buffer-local property
2253:                            properties.put(name, new PropValue(buf.toString(),
2254:                                    false));
2255:                            name = null;
2256:                        }
2257:                        buf.setLength(0);
2258:                        break;
2259:                    case '=':
2260:                        if (escape) {
2261:                            escape = false;
2262:                            buf.append('=');
2263:                            break;
2264:                        }
2265:                        name = buf.toString();
2266:                        buf.setLength(0);
2267:                        break;
2268:                    case '\\':
2269:                        if (escape)
2270:                            buf.append('\\');
2271:                        escape = !escape;
2272:                        break;
2273:                    case 'n':
2274:                        if (escape) {
2275:                            buf.append('\n');
2276:                            escape = false;
2277:                            break;
2278:                        }
2279:                    case 'r':
2280:                        if (escape) {
2281:                            buf.append('\r');
2282:                            escape = false;
2283:                            break;
2284:                        }
2285:                    case 't':
2286:                        if (escape) {
2287:                            buf.append('\t');
2288:                            escape = false;
2289:                            break;
2290:                        }
2291:                    default:
2292:                        buf.append(c);
2293:                        break;
2294:                    }
2295:                }
2296:            } //}}}
2297:
2298:            //{{{ getIndentRules() method
2299:            private List<IndentRule> getIndentRules(int line) {
2300:                String modeName = null;
2301:                TokenMarker.LineContext ctx = lineMgr.getLineContext(line);
2302:                if (ctx != null && ctx.rules != null)
2303:                    modeName = ctx.rules.getModeName();
2304:                if (modeName == null)
2305:                    modeName = tokenMarker.getMainRuleSet().getModeName();
2306:                return ModeProvider.instance.getMode(modeName).getIndentRules();
2307:            } //}}}
2308:
2309:            //}}}
2310:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.