Source Code Cross Referenced for BaseDocument.java in  » Swing-Library » abeille-forms-designer » org » netbeans » editor » 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 » abeille forms designer » org.netbeans.editor 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         *                 Sun Public License Notice
0003:         * 
0004:         * The contents of this file are subject to the Sun Public License
0005:         * Version 1.0 (the "License"). You may not use this file except in
0006:         * compliance with the License. A copy of the License is available at
0007:         * http://www.sun.com/
0008:         * 
0009:         * The Original Code is NetBeans. The Initial Developer of the Original
0010:         * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun
0011:         * Microsystems, Inc. All Rights Reserved.
0012:         */
0013:
0014:        package org.netbeans.editor;
0015:
0016:        import java.beans.PropertyChangeEvent;
0017:        import java.beans.PropertyChangeListener;
0018:        import java.io.IOException;
0019:        import java.io.Reader;
0020:        import java.io.Writer;
0021:        import java.util.ArrayList;
0022:        import java.util.Dictionary;
0023:        import java.util.Enumeration;
0024:        import java.util.Hashtable;
0025:
0026:        import javax.swing.event.DocumentEvent;
0027:        import javax.swing.event.EventListenerList;
0028:        import javax.swing.event.UndoableEditEvent;
0029:        import javax.swing.text.AbstractDocument;
0030:        import javax.swing.text.AttributeSet;
0031:        import javax.swing.text.BadLocationException;
0032:        import javax.swing.text.DefaultEditorKit;
0033:        import javax.swing.text.Document;
0034:        import javax.swing.text.Element;
0035:        import javax.swing.text.Position;
0036:        import javax.swing.text.StyleConstants;
0037:        import javax.swing.undo.CannotRedoException;
0038:        import javax.swing.undo.CannotUndoException;
0039:        import javax.swing.undo.CompoundEdit;
0040:        import javax.swing.undo.UndoableEdit;
0041:
0042:        /**
0043:         * Document implementation
0044:         * 
0045:         * @author Miloslav Metelka
0046:         * @version 1.00
0047:         */
0048:
0049:        public class BaseDocument extends AbstractDocument implements 
0050:                SettingsChangeListener {
0051:
0052:            /** Registry identification property */
0053:            public static final String ID_PROP = "id"; // NOI18N
0054:
0055:            /** Line separator property for reading files in */
0056:            public static final String READ_LINE_SEPARATOR_PROP = DefaultEditorKit.EndOfLineStringProperty;
0057:
0058:            /**
0059:             * Line separator property for writing content into files. If not set the
0060:             * writing defaults to the READ_LINE_SEPARATOR_PROP.
0061:             */
0062:            public static final String WRITE_LINE_SEPARATOR_PROP = "write-line-separator"; // NOI18N
0063:
0064:            /** File name property */
0065:            public static final String FILE_NAME_PROP = "file-name"; // NOI18N
0066:
0067:            /** Wrap search mark property */
0068:            public static final String WRAP_SEARCH_MARK_PROP = "wrap-search-mark"; // NOI18N
0069:
0070:            /**
0071:             * Undo manager property. This can be used to implement undo in a simple
0072:             * way. Default undo and redo actions try to get this property and perform
0073:             * undo and redo through it.
0074:             */
0075:            public static final String UNDO_MANAGER_PROP = "undo-manager"; // NOI18N
0076:
0077:            /**
0078:             * Kit class property. This can become useful for getting the settings that
0079:             * logicaly belonging to the document.
0080:             */
0081:            public static final String KIT_CLASS_PROP = "kit-class"; // NOI18N
0082:
0083:            /** String forward finder property */
0084:            public static final String STRING_FINDER_PROP = "string-finder"; // NOI18N
0085:
0086:            /** String backward finder property */
0087:            public static final String STRING_BWD_FINDER_PROP = "string-bwd-finder"; // NOI18N
0088:
0089:            /** Highlight search finder property. */
0090:            public static final String BLOCKS_FINDER_PROP = "blocks-finder"; // NOI18N
0091:
0092:            /**
0093:             * Maximum line width encountered during the initial read operation. This is
0094:             * filled by Analyzer and used by UI to set the correct initial width of the
0095:             * component. Values: java.lang.Integer
0096:             */
0097:            public static final String LINE_LIMIT_PROP = "line-limit"; // NOI18N
0098:
0099:            /**
0100:             * Size of the line batch. Line batch can be used at various places
0101:             * especially when processing lines by syntax scanner.
0102:             */
0103:            public static final String LINE_BATCH_SIZE = "line-batch-size"; // NOI18N
0104:
0105:            /** Line separator is marked by CR (Macintosh) */
0106:            public static final String LS_CR = "\r"; // NOI18N
0107:
0108:            /** Line separator is marked by LF (Unix) */
0109:            public static final String LS_LF = "\n"; // NOI18N
0110:
0111:            /** Line separator is marked by CR and LF (Windows) */
0112:            public static final String LS_CRLF = "\r\n"; // NOI18N
0113:
0114:            /**
0115:             * Maximum of concurrent read threads (other will wait until one of these
0116:             * will leave).
0117:             */
0118:            private static final int MAX_READ_THREADS = 10;
0119:
0120:            /** Write lock without write lock */
0121:            private static final String WRITE_LOCK_MISSING = "extWriteUnlock() without extWriteLock()"; // NOI18N
0122:
0123:            /** Debug modifications performed on the document */
0124:            private static final boolean debug = Boolean
0125:                    .getBoolean("netbeans.debug.editor.document"); // NOI18N
0126:            /** Debug the stack of calling of the insert/remove */
0127:            private static final boolean debugStack = Boolean
0128:                    .getBoolean("netbeans.debug.editor.document.stack"); // NOI18N
0129:
0130:            /**
0131:             * Document operations support class for this document. It presents the base
0132:             * synchronization level for most of the operations. Some of the operations
0133:             * are available through <tt>Utilities</tt> class.
0134:             */
0135:            DocOp op;
0136:
0137:            /** How many spaces should be displayed instead of '\t' character */
0138:            private int tabSize = SettingsDefaults.defaultTabSize.intValue();
0139:
0140:            /**
0141:             * Size of one indentation level. If this variable is null (value is not set
0142:             * in Settings, then the default algorithm will be used.
0143:             */
0144:            private Integer shiftWidth;
0145:
0146:            /** How many times current writer requested writing */
0147:            private int writeDeep;
0148:
0149:            /** How many times atomic writer requested writing */
0150:            private int atomicDepth;
0151:
0152:            /* Was the document initialized by reading? */
0153:            protected boolean inited;
0154:
0155:            /* Was the document modified by doing inert/remove */
0156:            protected boolean modified;
0157:
0158:            /** Listener list */
0159:            protected EventListenerList listenerList = new EventListenerList();
0160:
0161:            /** Listener to changes in find support */
0162:            PropertyChangeListener findSupportListener;
0163:
0164:            /** Default element - lazily inited */
0165:            protected BaseElement defaultRootElem;
0166:
0167:            private SyntaxSupport syntaxSupport;
0168:
0169:            /** Layer list for document level layers */
0170:            private DrawLayerList drawLayerList = new DrawLayerList();
0171:
0172:            /** Chain of document level bookmarks */
0173:            private MarkChain bookmarkChain;
0174:
0175:            /** Reset merging next created undoable edit to the last one. */
0176:            boolean undoMergeReset;
0177:
0178:            /** Kit class stored here */
0179:            Class kitClass;
0180:
0181:            /**
0182:             * Undo event for atomic events is fired after the successful atomic
0183:             * operation is finished. The changes are stored in this variable during the
0184:             * atomic operation. If the operation is broken, these edits are used to
0185:             * restore previous state.
0186:             */
0187:            private CompoundEdit atomicEdits;
0188:
0189:            private Acceptor identifierAcceptor;
0190:
0191:            private Acceptor whitespaceAcceptor;
0192:
0193:            private ArrayList syntaxList = new ArrayList();
0194:
0195:            /** List of the positions used by storePosition() */
0196:            private ArrayList posList = new ArrayList();
0197:
0198:            /** List of the integers marking the free positions in the posList. */
0199:            private ArrayList posFreeList = new ArrayList();
0200:
0201:            /** Root element of line elements representation */
0202:            protected LineRootElement lineRootElement;
0203:
0204:            private LeafElement composedTextElement;
0205:
0206:            /**
0207:             * Last document event to be undone. The field is filled by the lastly done
0208:             * modification undoable edit. BaseDocumentEvent.canUndo() checks this flag.
0209:             */
0210:            UndoableEdit lastModifyUndoEdit; // #8692 check last modify undo edit
0211:
0212:            /** List of annotations for this document. */
0213:            private Annotations annotations;
0214:
0215:            /** List of bookmarks attached to this document */
0216:            private Bookmarks bookmarks;
0217:
0218:            /**
0219:             * Create base document with a specified syntax.
0220:             * 
0221:             * @param kitClass
0222:             *            class used to initialize this document with proper settings
0223:             *            category based on the editor kit for which this document is
0224:             *            created
0225:             * @param syntax
0226:             *            syntax scanner to use with this document
0227:             */
0228:            public BaseDocument(Class kitClass, boolean addToRegistry) {
0229:                this (kitClass, addToRegistry, new DocOp());
0230:            }
0231:
0232:            private BaseDocument(Class kitClass, boolean addToRegistry, DocOp op) {
0233:                super (op);
0234:                this .op = op;
0235:                this .kitClass = kitClass;
0236:
0237:                setDocumentProperties(new LazyPropertyMap(
0238:                        getDocumentProperties()));
0239:
0240:                settingsChange(null); // initialize variables from settings
0241:                Settings.addSettingsChangeListener(this );
0242:
0243:                op.setDocument(this );
0244:
0245:                // Line separators default to platform ones
0246:                putProperty(READ_LINE_SEPARATOR_PROP, Analyzer.getPlatformLS());
0247:
0248:                bookmarkChain = new MarkChain(this ,
0249:                        DrawLayerFactory.BOOKMARK_LAYER_NAME);
0250:
0251:                // Add document draw-layers
0252:                addLayer(new DrawLayerFactory.SyntaxLayer(),
0253:                        DrawLayerFactory.SYNTAX_LAYER_VISIBILITY);
0254:
0255:                addLayer(new DrawLayerFactory.HighlightSearchLayer(),
0256:                        DrawLayerFactory.HIGHLIGHT_SEARCH_LAYER_VISIBILITY);
0257:
0258:                addLayer(new DrawLayerFactory.BookmarkLayer(),
0259:                        DrawLayerFactory.BOOKMARK_LAYER_VISIBILITY);
0260:
0261:                // Additional initialization of the document through the kit
0262:                BaseKit kit = BaseKit.getKit(kitClass);
0263:                if (kit != null) {
0264:                    kit.initDocument(this );
0265:                }
0266:
0267:                // Possibly add the document to registry
0268:                if (addToRegistry) {
0269:                    Registry.addDocument(this ); // add if created thru the kit
0270:                }
0271:
0272:                // Start listen on find-support
0273:                findSupportListener = new PropertyChangeListener() {
0274:                    public void propertyChange(PropertyChangeEvent evt) {
0275:                        findSupportChange(evt);
0276:                    }
0277:                };
0278:                FindSupport.getFindSupport().addPropertyChangeListener(
0279:                        findSupportListener);
0280:                findSupportChange(null); // update doc by find settings
0281:            }
0282:
0283:            private void findSupportChange(PropertyChangeEvent evt) {
0284:                // set all finders to null
0285:                putProperty(STRING_FINDER_PROP, null);
0286:                putProperty(STRING_BWD_FINDER_PROP, null);
0287:                putProperty(BLOCKS_FINDER_PROP, null);
0288:
0289:                DrawLayerFactory.HighlightSearchLayer hsl = (DrawLayerFactory.HighlightSearchLayer) findLayer(DrawLayerFactory.HIGHLIGHT_SEARCH_LAYER_NAME);
0290:
0291:                Boolean b = (Boolean) FindSupport.getFindSupport()
0292:                        .getPropertyNoInit(SettingsNames.FIND_HIGHLIGHT_SEARCH);
0293:                hsl.setEnabled((b != null) ? b.booleanValue() : false);
0294:
0295:                fireChangedUpdate(createDocumentEvent(0, getLength(),
0296:                        DocumentEvent.EventType.CHANGE)); // refresh
0297:                // whole
0298:                // document
0299:            }
0300:
0301:            /**
0302:             * Called when settings were changed. The method is called also in
0303:             * constructor, so the code must count with the evt being null.
0304:             */
0305:            public void settingsChange(SettingsChangeEvent evt) {
0306:                String settingName = (evt != null) ? evt.getSettingName()
0307:                        : null;
0308:
0309:                if (settingName == null
0310:                        || SettingsNames.TAB_SIZE.equals(settingName)) {
0311:                    tabSize = SettingsUtil.getPositiveInteger(kitClass,
0312:                            SettingsNames.TAB_SIZE,
0313:                            SettingsDefaults.defaultTabSize);
0314:                }
0315:
0316:                if (settingName == null
0317:                        || SettingsNames.INDENT_SHIFT_WIDTH.equals(settingName)) {
0318:                    Object shw = Settings.getValue(kitClass,
0319:                            SettingsNames.INDENT_SHIFT_WIDTH);
0320:                    if (shw instanceof  Integer) { // currently only Integer values are
0321:                        // supported
0322:                        shiftWidth = (Integer) shw;
0323:                    }
0324:                }
0325:
0326:                if (settingName == null
0327:                        || SettingsNames.READ_BUFFER_SIZE.equals(settingName)) {
0328:                    int readBufferSize = SettingsUtil.getPositiveInteger(
0329:                            kitClass, SettingsNames.READ_BUFFER_SIZE,
0330:                            SettingsDefaults.defaultReadBufferSize);
0331:                    putProperty(SettingsNames.READ_BUFFER_SIZE, new Integer(
0332:                            readBufferSize));
0333:                }
0334:
0335:                if (settingName == null
0336:                        || SettingsNames.WRITE_BUFFER_SIZE.equals(settingName)) {
0337:                    int writeBufferSize = SettingsUtil.getPositiveInteger(
0338:                            kitClass, SettingsNames.WRITE_BUFFER_SIZE,
0339:                            SettingsDefaults.defaultWriteBufferSize);
0340:                    putProperty(SettingsNames.WRITE_BUFFER_SIZE, new Integer(
0341:                            writeBufferSize));
0342:                }
0343:
0344:                if (settingName == null
0345:                        || SettingsNames.MARK_DISTANCE.equals(settingName)) {
0346:                    int markDistance = SettingsUtil.getPositiveInteger(
0347:                            kitClass, SettingsNames.MARK_DISTANCE,
0348:                            SettingsDefaults.defaultMarkDistance);
0349:                    putProperty(SettingsNames.MARK_DISTANCE, new Integer(
0350:                            markDistance));
0351:                }
0352:
0353:                if (settingName == null
0354:                        || SettingsNames.MAX_MARK_DISTANCE.equals(settingName)) {
0355:                    int maxMarkDistance = SettingsUtil.getPositiveInteger(
0356:                            kitClass, SettingsNames.MAX_MARK_DISTANCE,
0357:                            SettingsDefaults.defaultMaxMarkDistance);
0358:                    putProperty(SettingsNames.MAX_MARK_DISTANCE, new Integer(
0359:                            maxMarkDistance));
0360:                }
0361:
0362:                if (settingName == null
0363:                        || SettingsNames.MIN_MARK_DISTANCE.equals(settingName)) {
0364:                    int minMarkDistance = SettingsUtil.getPositiveInteger(
0365:                            kitClass, SettingsNames.MIN_MARK_DISTANCE,
0366:                            SettingsDefaults.defaultMinMarkDistance);
0367:                    putProperty(SettingsNames.MIN_MARK_DISTANCE, new Integer(
0368:                            minMarkDistance));
0369:                }
0370:
0371:                if (settingName == null
0372:                        || SettingsNames.READ_MARK_DISTANCE.equals(settingName)) {
0373:                    int readMarkDistance = SettingsUtil.getPositiveInteger(
0374:                            kitClass, SettingsNames.READ_MARK_DISTANCE,
0375:                            SettingsDefaults.defaultReadMarkDistance);
0376:                    putProperty(SettingsNames.READ_MARK_DISTANCE, new Integer(
0377:                            readMarkDistance));
0378:                }
0379:
0380:                if (settingName == null
0381:                        || SettingsNames.SYNTAX_UPDATE_BATCH_SIZE
0382:                                .equals(settingName)) {
0383:                    int syntaxUpdateBatchSize = SettingsUtil
0384:                            .getPositiveInteger(
0385:                                    kitClass,
0386:                                    SettingsNames.SYNTAX_UPDATE_BATCH_SIZE,
0387:                                    SettingsDefaults.defaultSyntaxUpdateBatchSize);
0388:                    putProperty(SettingsNames.SYNTAX_UPDATE_BATCH_SIZE,
0389:                            new Integer(syntaxUpdateBatchSize));
0390:                }
0391:
0392:                if (settingName == null
0393:                        || SettingsNames.LINE_BATCH_SIZE.equals(settingName)) {
0394:                    int lineBatchSize = SettingsUtil.getPositiveInteger(
0395:                            kitClass, SettingsNames.LINE_BATCH_SIZE,
0396:                            SettingsDefaults.defaultLineBatchSize);
0397:                    putProperty(SettingsNames.LINE_BATCH_SIZE, new Integer(
0398:                            lineBatchSize));
0399:                }
0400:
0401:                if (settingName == null
0402:                        || SettingsNames.IDENTIFIER_ACCEPTOR
0403:                                .equals(settingName)) {
0404:                    identifierAcceptor = SettingsUtil.getAcceptor(kitClass,
0405:                            SettingsNames.IDENTIFIER_ACCEPTOR,
0406:                            AcceptorFactory.LETTER_DIGIT);
0407:                }
0408:
0409:                if (settingName == null
0410:                        || SettingsNames.WHITESPACE_ACCEPTOR
0411:                                .equals(settingName)) {
0412:                    whitespaceAcceptor = SettingsUtil.getAcceptor(kitClass,
0413:                            SettingsNames.WHITESPACE_ACCEPTOR,
0414:                            AcceptorFactory.WHITESPACE);
0415:                }
0416:
0417:                boolean stopOnEOL = SettingsUtil.getBoolean(kitClass,
0418:                        SettingsNames.WORD_MOVE_NEWLINE_STOP, true);
0419:                if (settingName == null
0420:                        || SettingsNames.NEXT_WORD_FINDER.equals(settingName)) {
0421:                    putProperty(SettingsNames.NEXT_WORD_FINDER, SettingsUtil
0422:                            .getValue(kitClass, SettingsNames.NEXT_WORD_FINDER,
0423:                                    new FinderFactory.NextWordFwdFinder(this ,
0424:                                            stopOnEOL, false)));
0425:                }
0426:
0427:                if (settingName == null
0428:                        || SettingsNames.PREVIOUS_WORD_FINDER
0429:                                .equals(settingName)) {
0430:                    putProperty(SettingsNames.PREVIOUS_WORD_FINDER,
0431:                            SettingsUtil.getValue(kitClass,
0432:                                    SettingsNames.PREVIOUS_WORD_FINDER,
0433:                                    new FinderFactory.PreviousWordBwdFinder(
0434:                                            this , stopOnEOL, false)));
0435:                }
0436:
0437:            }
0438:
0439:            Syntax getFreeSyntax() {
0440:                synchronized (syntaxList) {
0441:                    int cnt = syntaxList.size();
0442:                    return (cnt > 0) ? (Syntax) syntaxList.remove(cnt - 1)
0443:                            : BaseKit.getKit(kitClass).createSyntax(this );
0444:                }
0445:            }
0446:
0447:            void releaseSyntax(Syntax syntax) {
0448:                synchronized (syntaxList) {
0449:                    syntaxList.add(syntax);
0450:                }
0451:            }
0452:
0453:            /** Get the formatter for this document. */
0454:            public Formatter getFormatter() {
0455:                return Formatter.getFormatter(kitClass);
0456:            }
0457:
0458:            public SyntaxSupport getSyntaxSupport() {
0459:                if (syntaxSupport == null) {
0460:                    syntaxSupport = BaseKit.getKit(kitClass)
0461:                            .createSyntaxSupport(this );
0462:                }
0463:                return syntaxSupport;
0464:            }
0465:
0466:            /**
0467:             * Perform any generic text processing. The advantage of this method is that
0468:             * it allows the text to processed in line batches. The initial size of the
0469:             * batch is given by the SettingsNames.LINE_BATCH_SIZE. The
0470:             * TextBatchProcessor.processTextBatch() method is called for every text
0471:             * batch. If the method returns true, it means the processing should
0472:             * continue with the next batch of text which will have double line count
0473:             * compared to the previous one. This guarantees there will be not too many
0474:             * batches so the processing should be more efficient.
0475:             * 
0476:             * @param tbp
0477:             *            text batch processor to be used to process the text batches
0478:             * @param startPos
0479:             *            starting position of the processing.
0480:             * @param endPos
0481:             *            ending position of the processing. This can be -1 to signal
0482:             *            the end of document. If the endPos is lower than startPos then
0483:             *            the batches are created in the backward direction.
0484:             * @return the returned value from the last tpb.processTextBatch() call. The
0485:             *         -1 will be returned for (startPos == endPos).
0486:             */
0487:            public int processText(TextBatchProcessor tbp, int startPos,
0488:                    int endPos) throws BadLocationException {
0489:                if (endPos == -1) {
0490:                    endPos = getLength();
0491:                }
0492:                int batchLineCnt = ((Integer) getProperty(SettingsNames.LINE_BATCH_SIZE))
0493:                        .intValue();
0494:                int batchStart = startPos;
0495:                int ret = -1;
0496:                if (startPos < endPos) { // batching in forward direction
0497:                    while (ret < 0 && batchStart < endPos) {
0498:                        int batchEnd = Math.min(Utilities.getRowStart(this ,
0499:                                batchStart, batchLineCnt), endPos);
0500:                        if (batchEnd == -1) { // getRowStart() returned -1
0501:                            batchEnd = endPos;
0502:                        }
0503:                        ret = tbp.processTextBatch(this , batchStart, batchEnd,
0504:                                (batchEnd == endPos));
0505:                        batchLineCnt *= 2; // double the scanned area
0506:                        batchStart = batchEnd;
0507:                    }
0508:                } else {
0509:                    while (ret < 0 && batchStart > endPos) {
0510:                        int batchEnd = Math.max(Utilities.getRowStart(this ,
0511:                                batchStart, -batchLineCnt), endPos);
0512:                        ret = tbp.processTextBatch(this , batchStart, batchEnd,
0513:                                (batchEnd == endPos));
0514:                        batchLineCnt *= 2; // double the scanned area
0515:                        batchStart = batchEnd;
0516:                    }
0517:                }
0518:                return ret;
0519:            }
0520:
0521:            public boolean isIdentifierPart(char ch) {
0522:                return identifierAcceptor.accept(ch);
0523:            }
0524:
0525:            public boolean isWhitespace(char ch) {
0526:                return whitespaceAcceptor.accept(ch);
0527:            }
0528:
0529:            /**
0530:             * Length of document.
0531:             * 
0532:             * @return number of characters >= 0
0533:             */
0534:            public final int getLength() {
0535:                return op.length();
0536:            }
0537:
0538:            /**
0539:             * Create the mark for the given position and store it in the list. The
0540:             * position can be later retrieved through its ID.
0541:             */
0542:            int storePosition(int pos) throws BadLocationException {
0543:                Mark mark = op.insertMark(pos, false);
0544:                int ind;
0545:                if (posFreeList.size() > 0) {
0546:                    ind = ((Integer) posFreeList.remove(posFreeList.size() - 1))
0547:                            .intValue();
0548:                    posList.set(ind, mark);
0549:                } else { // no free indexes
0550:                    ind = posList.size();
0551:                    posList.add(mark);
0552:                }
0553:                return ind;
0554:            }
0555:
0556:            int getStoredPosition(int posID) {
0557:                if (posID < 0 || posID >= posList.size()) {
0558:                    return -1;
0559:                }
0560:
0561:                try {
0562:                    return ((Mark) posList.get(posID)).getOffset();
0563:                } catch (InvalidMarkException e) {
0564:                    return -1;
0565:                }
0566:            }
0567:
0568:            void removeStoredPosition(int posID) {
0569:                if (posID >= 0 || posID < posList.size()) {
0570:                    Mark mark = (Mark) posList.get(posID);
0571:                    posList.set(posID, null); // clear the index
0572:                    posFreeList.add(new Integer(posID));
0573:
0574:                    // Remove the mark #19429
0575:                    try {
0576:                        mark.remove();
0577:                    } catch (InvalidMarkException e) {
0578:                    }
0579:                }
0580:            }
0581:
0582:            /** Inserts string into document */
0583:            public void insertString(int offset, String text, AttributeSet a)
0584:                    throws BadLocationException {
0585:                if (text == null || text.length() == 0) {
0586:                    return;
0587:                }
0588:
0589:                // Check offset correctness
0590:                if (offset < 0 || offset > getLength()) {
0591:                    throw new BadLocationException("Wrong insert position",
0592:                            offset); // NOI18N
0593:                }
0594:
0595:                // possible CR-LF conversion
0596:                text = Analyzer.convertLSToLF(text);
0597:
0598:                // Perform the insert
0599:                extWriteLock();
0600:                try {
0601:
0602:                    preInsertCheck(offset, text, a);
0603:
0604:                    // Do the real insert into the content
0605:                    UndoableEdit edit = op.insertString(offset, text);
0606:
0607:                    if (debug) {
0608:                        System.err.println("BaseDocument.insertString(): doc="
0609:                                + this  // NOI18N
0610:                                + (modified ? "" : " - first modification") // NOI18N
0611:                                + ", offset=" + offset // NOI18N
0612:                                + ", text='" + text + "'" // NOI18N
0613:                        );
0614:                    }
0615:                    if (debugStack) {
0616:                        Thread.dumpStack();
0617:                    }
0618:
0619:                    BaseDocumentEvent evt = createDocumentEvent(offset, text
0620:                            .length(), DocumentEvent.EventType.INSERT);
0621:                    if (edit != null) {
0622:                        evt.addEdit(edit);
0623:
0624:                        lastModifyUndoEdit = edit; // #8692 check last modify undo edit
0625:                    }
0626:
0627:                    modified = true;
0628:
0629:                    if (atomicDepth > 0) {
0630:                        if (atomicEdits == null) {
0631:                            atomicEdits = new AtomicCompoundEdit();
0632:                        }
0633:                        atomicEdits.addEdit(evt); // will be added
0634:                    }
0635:
0636:                    insertUpdate(evt, a);
0637:
0638:                    evt.end();
0639:
0640:                    fireInsertUpdate(evt);
0641:
0642:                    boolean isComposedText = ((a != null) && (a
0643:                            .isDefined(StyleConstants.ComposedTextAttribute)));
0644:
0645:                    if (atomicDepth == 0 && !isComposedText) { // !!! check
0646:                        fireUndoableEditUpdate(new UndoableEditEvent(this , evt));
0647:                    }
0648:                } finally {
0649:                    extWriteUnlock();
0650:                }
0651:            }
0652:
0653:            /** Removes portion of a document */
0654:            public void remove(int offset, int len) throws BadLocationException {
0655:                if (len > 0) {
0656:                    extWriteLock();
0657:                    try {
0658:                        int docLen = getLength();
0659:                        if (offset < 0 || offset > docLen) {
0660:                            throw new BadLocationException(
0661:                                    "Wrong remove position", offset); // NOI18N
0662:                        }
0663:                        if (offset + len > docLen) {
0664:                            throw new BadLocationException(
0665:                                    "End offset of removed text is too big",
0666:                                    offset + len); // NOI18N
0667:                        }
0668:
0669:                        preRemoveCheck(offset, len);
0670:
0671:                        BaseDocumentEvent evt = createDocumentEvent(offset,
0672:                                len, DocumentEvent.EventType.REMOVE);
0673:
0674:                        removeUpdate(evt);
0675:
0676:                        UndoableEdit edit = op.remove(offset, len);
0677:                        if (edit != null) {
0678:                            evt.addEdit(edit);
0679:
0680:                            lastModifyUndoEdit = edit; // #8692 check last modify undo
0681:                            // edit
0682:                        }
0683:
0684:                        if (debug) {
0685:                            System.err.println("BaseDocument.remove(): doc="
0686:                                    + this  // NOI18N
0687:                                    + ", offset=" + offset + ", len=" + len); // NOI18N
0688:                        }
0689:                        if (debugStack) {
0690:                            Thread.dumpStack();
0691:                        }
0692:
0693:                        if (atomicDepth > 0) { // add edits as soon as possible
0694:                            if (atomicEdits == null) {
0695:                                atomicEdits = new AtomicCompoundEdit();
0696:                            }
0697:                            atomicEdits.addEdit(evt); // will be added
0698:                        }
0699:
0700:                        postRemoveUpdate(evt);
0701:
0702:                        evt.end();
0703:
0704:                        fireRemoveUpdate(evt);
0705:                        if (atomicDepth == 0) {
0706:                            fireUndoableEditUpdate(new UndoableEditEvent(this ,
0707:                                    evt));
0708:                        }
0709:                    } finally {
0710:                        extWriteUnlock();
0711:                    }
0712:                }
0713:            }
0714:
0715:            /**
0716:             * This method is called automatically before the document insertion occurs
0717:             * and can be used to revoke the insertion before it occurs by throwing the
0718:             * <tt>BadLocationException</tt>.
0719:             * 
0720:             * @param offset
0721:             *            position where the insertion will be done
0722:             * @param text
0723:             *            string to be inserted
0724:             * @param a
0725:             *            attributes of the inserted text
0726:             */
0727:            protected void preInsertCheck(int offset, String text,
0728:                    AttributeSet a) throws BadLocationException {
0729:            }
0730:
0731:            /**
0732:             * This method is called automatically before the document removal occurs
0733:             * and can be used to revoke the removal before it occurs by throwing the
0734:             * <tt>BadLocationException</tt>.
0735:             * 
0736:             * @param offset
0737:             *            position where the insertion will be done
0738:             * @param len
0739:             *            length of the removal
0740:             */
0741:            protected void preRemoveCheck(int offset, int len)
0742:                    throws BadLocationException {
0743:            }
0744:
0745:            public String getText(int[] block) throws BadLocationException {
0746:                return getText(block[0], block[1] - block[0]);
0747:            }
0748:
0749:            public char[] getChars(int pos, int len)
0750:                    throws BadLocationException {
0751:                return op.getChars(pos, len);
0752:            }
0753:
0754:            public char[] getChars(int[] block) throws BadLocationException {
0755:                return getChars(block[0], block[1] - block[0]);
0756:            }
0757:
0758:            public void getChars(int pos, char ret[], int offset, int len)
0759:                    throws BadLocationException {
0760:                op.getChars(pos, ret, offset, len);
0761:            }
0762:
0763:            /**
0764:             * Find something in document using a finder.
0765:             * 
0766:             * @param finder
0767:             *            finder to be used for the search
0768:             * @param startPos
0769:             *            position in the document where the search will start
0770:             * @param limitPos
0771:             *            position where the search will be end with reporting that
0772:             *            nothing was found.
0773:             */
0774:            public int find(Finder finder, int startPos, int limitPos)
0775:                    throws BadLocationException {
0776:                if (finder instanceof  AdjustFinder) {
0777:                    int docLen = getLength();
0778:                    if (limitPos == -1) {
0779:                        limitPos = docLen;
0780:                    }
0781:                    if (startPos == -1) {
0782:                        startPos = docLen;
0783:                    }
0784:
0785:                    if (startPos == limitPos) { // stop immediately
0786:                        finder.reset(); // reset() should be called in all the cases
0787:                        return -1; // must stop here because wouldn't know if fwd/bwd
0788:                        // search?
0789:                    }
0790:
0791:                    boolean forward = (startPos < limitPos);
0792:                    startPos = ((AdjustFinder) finder).adjustStartPos(this ,
0793:                            startPos);
0794:                    limitPos = ((AdjustFinder) finder).adjustLimitPos(this ,
0795:                            limitPos);
0796:                    boolean voidSearch = (forward ? (startPos >= limitPos)
0797:                            : (startPos <= limitPos));
0798:                    if (voidSearch) {
0799:                        finder.reset();
0800:                        return -1;
0801:                    }
0802:                }
0803:
0804:                return op.find(finder, startPos, limitPos);
0805:            }
0806:
0807:            /** Fire the change event to repaint the given block of text. */
0808:            public void repaintBlock(int startOffset, int endOffset) {
0809:                BaseDocumentEvent evt = createDocumentEvent(startOffset,
0810:                        endOffset - startOffset, DocumentEvent.EventType.CHANGE);
0811:                fireChangedUpdate(evt);
0812:            }
0813:
0814:            public void print(PrintContainer container) {
0815:                readLock();
0816:                try {
0817:                    EditorUI editorUI = BaseKit.getKit(kitClass)
0818:                            .createPrintEditorUI(this );
0819:                    DrawGraphics.PrintDG printDG = new DrawGraphics.PrintDG(
0820:                            container);
0821:                    DrawEngine.getDrawEngine().draw(printDG, editorUI, 0,
0822:                            getLength(), 0, 0, Integer.MAX_VALUE);
0823:                } catch (BadLocationException e) {
0824:                    e.printStackTrace();
0825:                } finally {
0826:                    readUnlock();
0827:                }
0828:            }
0829:
0830:            /** Create biased position in document */
0831:            public Position createPosition(int offset, Position.Bias bias)
0832:                    throws BadLocationException {
0833:                return op.createPosition(offset, bias);
0834:            }
0835:
0836:            /** Return array of root elements - usually only one */
0837:            public Element[] getRootElements() {
0838:                Element[] elems = new Element[1];
0839:                elems[0] = getDefaultRootElement();
0840:                return elems;
0841:            }
0842:
0843:            /** Return default root element */
0844:            public Element getDefaultRootElement() {
0845:                if (defaultRootElem == null) {
0846:                    defaultRootElem = new org.netbeans.editor.LeafElement(this ,
0847:                            null, null, 0, getLength(), false, false);
0848:                }
0849:                return defaultRootElem;
0850:            }
0851:
0852:            /** Runs the runnable under read lock. */
0853:            public void render(Runnable r) {
0854:                readLock();
0855:                try {
0856:                    r.run();
0857:                } finally {
0858:                    readUnlock();
0859:                }
0860:            }
0861:
0862:            /**
0863:             * Runs the runnable under write lock. This is a stronger version of the
0864:             * runAtomicAsUser() method, because if there any locked sections in the
0865:             * documents this methods breaks the modification locks and modifies the
0866:             * document. If there are any excpeptions thrown during the processing of
0867:             * the runnable, all the document modifications are rolled back
0868:             * automatically.
0869:             */
0870:            public void runAtomic(Runnable r) {
0871:                runAtomicAsUser(r);
0872:            }
0873:
0874:            /**
0875:             * Runs the runnable under write lock. If there are any excpeptions thrown
0876:             * during the processing of the runnable, all the document modifications are
0877:             * rolled back automatically.
0878:             */
0879:            public void runAtomicAsUser(Runnable r) {
0880:                boolean completed = false;
0881:                atomicLock();
0882:                try {
0883:                    r.run();
0884:                    completed = true;
0885:                } finally {
0886:                    try {
0887:                        if (!completed) {
0888:                            breakAtomicLock();
0889:                        }
0890:                    } finally {
0891:                        atomicUnlock();
0892:                    }
0893:                }
0894:            }
0895:
0896:            /**
0897:             * Insert contents of reader at specified position into document.
0898:             * 
0899:             * @param reader
0900:             *            reader from which data will be read
0901:             * @param pos
0902:             *            on which position that data will be inserted
0903:             */
0904:            public void read(Reader reader, int pos) throws IOException,
0905:                    BadLocationException {
0906:                extWriteLock();
0907:                try {
0908:
0909:                    if (pos < 0 || pos > getLength()) {
0910:                        throw new BadLocationException("BaseDocument.read()",
0911:                                pos); // NOI18N
0912:                    }
0913:
0914:                    if (inited || modified) { // was the document already initialized?
0915:                        Analyzer.read(this , reader, pos);
0916:                    } else { // not initialized yet, we can use initialRead()
0917:                        Analyzer.initialRead(this , reader, true);
0918:                        BaseDocumentEvent evt = createDocumentEvent(0, 0,
0919:                                DocumentEvent.EventType.INSERT);
0920:                        evt.end();
0921:                        fireInsertUpdate(evt); // fire the insert event with zero
0922:                        // length to notify about the change
0923:                        inited = true; // initialized but not modified
0924:                    }
0925:                } finally {
0926:                    extWriteUnlock();
0927:                }
0928:            }
0929:
0930:            /**
0931:             * Write part of the document into specified writer.
0932:             * 
0933:             * @param writer
0934:             *            writer into which data will be written.
0935:             * @param pos
0936:             *            from which position get the data
0937:             * @param len
0938:             *            how many characters write
0939:             */
0940:            public void write(Writer writer, int pos, int len)
0941:                    throws IOException, BadLocationException {
0942:                readLock();
0943:                try {
0944:
0945:                    if ((pos < 0) || ((pos + len) > getLength())) {
0946:                        throw new BadLocationException("BaseDocument.write()",
0947:                                pos); // NOI18N
0948:                    }
0949:                    Analyzer.write(this , writer, pos, len);
0950:                    writer.flush();
0951:                } finally {
0952:                    readUnlock();
0953:                }
0954:            }
0955:
0956:            /**
0957:             * Invalidate the state-infos in all the syntax-marks in the whole document.
0958:             * The Syntax can call this method if it changes its internal state in the
0959:             * way that affects the future returned tokens. The syntax-state-info in all
0960:             * the marks is reset and it will be lazily restored when necessary.
0961:             */
0962:            public void invalidateSyntaxMarks() {
0963:                extWriteLock();
0964:                try {
0965:                    op.invalidateSyntaxMarks();
0966:                    repaintBlock(0, getLength());
0967:                } finally {
0968:                    extWriteUnlock();
0969:                }
0970:            }
0971:
0972:            /**
0973:             * Get the number of spaces the TAB character ('\t') visually represents.
0974:             * This is related to <code>SettingsNames.TAB_SIZE</code> setting.
0975:             */
0976:            public int getTabSize() {
0977:                return tabSize;
0978:            }
0979:
0980:            /**
0981:             * Get the width of one indentation level. The algorithm first checks
0982:             * whether there's a value for the INDENT_SHIFT_WIDTH setting. If so it uses
0983:             * it, otherwise it uses <code>formatter.getSpacesPerTab()</code>.
0984:             * 
0985:             * @see getTabSize()
0986:             * @see Formatter.getSpacesPerTab()
0987:             */
0988:            public int getShiftWidth() {
0989:                if (shiftWidth != null) {
0990:                    return shiftWidth.intValue();
0991:
0992:                } else {
0993:                    return getFormatter().getSpacesPerTab();
0994:                }
0995:            }
0996:
0997:            public final Class getKitClass() {
0998:                return kitClass;
0999:            }
1000:
1001:            /**
1002:             * This method prohibits merging of the next document modification with the
1003:             * previous one even if it would be normally possible.
1004:             */
1005:            public void resetUndoMerge() {
1006:                undoMergeReset = true;
1007:            }
1008:
1009:            /*
1010:             * Defined because of the hack for undo() in the BaseDocumentEvent.
1011:             */
1012:            protected void fireChangedUpdate(DocumentEvent e) {
1013:                super .fireChangedUpdate(e);
1014:            }
1015:
1016:            protected void fireInsertUpdate(DocumentEvent e) {
1017:                super .fireInsertUpdate(e);
1018:            }
1019:
1020:            protected void fireRemoveUpdate(DocumentEvent e) {
1021:                super .fireRemoveUpdate(e);
1022:            }
1023:
1024:            /**
1025:             * Extended write locking of the document allowing reentrant write lock
1026:             * acquiring.
1027:             */
1028:            public synchronized final void extWriteLock() {
1029:                if (Thread.currentThread() != getCurrentWriter()) {
1030:                    super .writeLock();
1031:                } else { // inner locking block
1032:                    writeDeep++; // only increase write deepness
1033:                }
1034:            }
1035:
1036:            /**
1037:             * Extended write unlocking.
1038:             * 
1039:             * @see extWriteLock()
1040:             */
1041:            public synchronized final void extWriteUnlock() {
1042:                if (Thread.currentThread() != getCurrentWriter()) {
1043:                    throw new RuntimeException(WRITE_LOCK_MISSING);
1044:                }
1045:
1046:                if (writeDeep == 0) { // most outer locking block
1047:                    super .writeUnlock();
1048:                } else { // just inner locking block
1049:                    writeDeep--;
1050:                }
1051:            }
1052:
1053:            public synchronized final void atomicLock() {
1054:                extWriteLock();
1055:                atomicDepth++;
1056:            }
1057:
1058:            public synchronized final void atomicUnlock() {
1059:                extWriteUnlock();
1060:                if (atomicDepth == 0) {
1061:                    return;
1062:                }
1063:                if (--atomicDepth == 0) { // must fire possible undo event
1064:                    if (atomicEdits != null) {
1065:                        atomicEdits.end();
1066:                        fireUndoableEditUpdate(new UndoableEditEvent(this ,
1067:                                atomicEdits));
1068:                        atomicEdits = null;
1069:                    }
1070:                }
1071:            }
1072:
1073:            /**
1074:             * Is the document currently atomically locked? It's not synced as this
1075:             * method must be called only from writer thread.
1076:             */
1077:            public final boolean isAtomicLock() {
1078:                return (atomicDepth > 0);
1079:            }
1080:
1081:            /**
1082:             * Break the atomic lock so that doc is no longer in atomic mode. All the
1083:             * performed changes are rolled back automatically. Even after calling this
1084:             * method, the atomicUnlock() must still be called. This method is not
1085:             * synced as it must be called only from writer thread.
1086:             */
1087:            public final void breakAtomicLock() {
1088:                atomicDepth = 0;
1089:                if (atomicEdits != null) {
1090:                    atomicEdits.end();
1091:                    atomicEdits.undo();
1092:                    atomicEdits = null;
1093:                }
1094:            }
1095:
1096:            protected final int getAtomicDepth() {
1097:                return atomicDepth;
1098:            }
1099:
1100:            protected BaseDocumentEvent createDocumentEvent(int pos,
1101:                    int length, DocumentEvent.EventType type) {
1102:                return new BaseDocumentEvent(this , pos, length, type);
1103:            }
1104:
1105:            /**
1106:             * Was the document modified by either insert/remove but not the initial
1107:             * read)?
1108:             */
1109:            public boolean isModified() {
1110:                return modified;
1111:            }
1112:
1113:            /** Get the layer with the specified name */
1114:            public DrawLayer findLayer(String layerName) {
1115:                return drawLayerList.findLayer(layerName);
1116:            }
1117:
1118:            public boolean addLayer(DrawLayer layer, int visibility) {
1119:                if (drawLayerList.add(layer, visibility)) {
1120:                    BaseDocumentEvent evt = createDocumentEvent(0, 0,
1121:                            DocumentEvent.EventType.CHANGE);
1122:                    evt.addEdit(new BaseDocumentEvent.DrawLayerChange(layer
1123:                            .getName(), visibility));
1124:                    fireChangedUpdate(evt);
1125:                    return true;
1126:                } else {
1127:                    return false;
1128:                }
1129:            }
1130:
1131:            final DrawLayerList getDrawLayerList() {
1132:                return drawLayerList;
1133:            }
1134:
1135:            /** Toggle the bookmark for the current line */
1136:            public boolean toggleBookmark(int pos) throws BadLocationException {
1137:                pos = Utilities.getRowStart(this , pos);
1138:                boolean marked = bookmarkChain.toggleMark(pos);
1139:                BaseDocumentEvent evt = createDocumentEvent(pos, 0,
1140:                        DocumentEvent.EventType.CHANGE);
1141:                fireChangedUpdate(evt);
1142:                return marked;
1143:            }
1144:
1145:            /**
1146:             * Get the position of the next bookmark.
1147:             * 
1148:             * @pos position from which to search
1149:             * @wrap wrap around the end of document
1150:             * @return position of the next bookmark or -1 if there is no mark
1151:             */
1152:            public int getNextBookmark(int pos, boolean wrap)
1153:                    throws BadLocationException {
1154:                try {
1155:                    pos = Utilities.getRowStart(this , pos);
1156:                    int rel = bookmarkChain.compareMark(pos);
1157:                    MarkFactory.ChainDrawMark mark = bookmarkChain.getCurMark();
1158:                    if (rel <= 0) { // right at this line, go next
1159:                        if (mark != null) {
1160:                            if (mark.next != null) {
1161:                                return mark.next.getOffset();
1162:                            } else { // last bookmark
1163:                                return (wrap && bookmarkChain.chain != null) ? bookmarkChain.chain
1164:                                        .getOffset()
1165:                                        : -1;
1166:                            }
1167:                        } else { // no marks
1168:                            return -1;
1169:                        }
1170:                    } else { // mark after pos
1171:                        return mark.getOffset();
1172:                    }
1173:                } catch (InvalidMarkException e) {
1174:                    if (Boolean.getBoolean("netbeans.debug.exceptions")) { // NOI18N
1175:                        e.printStackTrace();
1176:                    }
1177:                    return 0;
1178:                }
1179:            }
1180:
1181:            private LineRootElement getLineRootElement() {
1182:                if (lineRootElement == null) {
1183:                    lineRootElement = new LineRootElement();
1184:                }
1185:                return lineRootElement;
1186:            }
1187:
1188:            public Element getParagraphElement(int pos) {
1189:                return getLineRootElement().getElement(
1190:                        getLineRootElement().getElementIndex(pos));
1191:            }
1192:
1193:            /**
1194:             * Returns object which represent list of annotations which are attached to
1195:             * this document.
1196:             * 
1197:             * @return object which represent attached annotations
1198:             */
1199:            public synchronized Annotations getAnnotations() {
1200:                if (annotations == null) {
1201:                    annotations = new Annotations(this );
1202:                }
1203:                return annotations;
1204:            }
1205:
1206:            /**
1207:             * Returns object which represent list of annotations which are attached to
1208:             * this document.
1209:             * 
1210:             * @return object which represent attached annotations
1211:             */
1212:            public synchronized Bookmarks getBookmarks() {
1213:                if (bookmarks == null) {
1214:                    bookmarks = new Bookmarks();
1215:                }
1216:                return bookmarks;
1217:            }
1218:
1219:            public String toString() {
1220:                return super .toString() + ", kitClass=" + getKitClass() // NOI18N
1221:                        + ", docLen=" + getLength(); // NOI18N
1222:            }
1223:
1224:            /** Detailed debug info about the document */
1225:            public String toStringDetail() {
1226:                return toString();
1227:            }
1228:
1229:            /** Substitution for (each line = element) behavior */
1230:            class LineRootElement implements  Element {
1231:
1232:                public Document getDocument() {
1233:                    return BaseDocument.this ;
1234:                }
1235:
1236:                public Element getParentElement() {
1237:                    return null;
1238:                }
1239:
1240:                public String getName() {
1241:                    return "line-elements-root"; // NOI18N
1242:                }
1243:
1244:                public AttributeSet getAttributes() {
1245:                    return null;
1246:                }
1247:
1248:                public int getStartOffset() {
1249:                    return 0;
1250:                }
1251:
1252:                public int getEndOffset() {
1253:                    return getLength();
1254:                }
1255:
1256:                public int getElementIndex(int offset) {
1257:                    try {
1258:                        return Utilities.getLineOffset(BaseDocument.this ,
1259:                                offset);
1260:                    } catch (BadLocationException e) {
1261:                        return 0;
1262:                    }
1263:                }
1264:
1265:                public int getElementCount() {
1266:                    return Utilities.getRowCount(BaseDocument.this );
1267:                }
1268:
1269:                public Element getElement(int index) {
1270:                    if (index < 0) {
1271:                        // throwing IOOBE to be compatible with swing's AbstractDocument
1272:                        // that does not check index < 0
1273:                        throw new IndexOutOfBoundsException("Line index="
1274:                                + index + " must be >= 0"); // NOI18N
1275:                    }
1276:
1277:                    try {
1278:                        int startPos = Utilities.getRowStartFromLineOffset(
1279:                                BaseDocument.this , index);
1280:
1281:                        if (startPos < 0) { // line index was invalid
1282:                            /*
1283:                             * throw new IllegalArgumentException("Line index=" + index //
1284:                             * NOI18N + " is invalid. Maximum index is " // NOI18N +
1285:                             * (Utilities.getRowCount(BaseDocument.this) - 1) + " in the
1286:                             * document " // NOI18N +
1287:                             * Utilities.debugDocument(BaseDocument.this) + "." // NOI18N );
1288:                             */
1289:
1290:                            return getElement(Utilities
1291:                                    .getRowCount(BaseDocument.this ) - 1); // last
1292:                            // line
1293:
1294:                        }
1295:
1296:                        LineElement elem = null;
1297:                        MarkFactory.LineMark mark = (MarkFactory.LineMark) op
1298:                                .getOffsetMark(startPos,
1299:                                        MarkFactory.LineMark.class);
1300:                        if (mark != null) {
1301:                            elem = mark.lineElemRef; // non-weak ref due to #17351
1302:                        }
1303:
1304:                        if (elem == null) {
1305:                            // Create the mark if necessary
1306:                            if (mark == null) {
1307:                                mark = new MarkFactory.LineMark();
1308:                                elem = new LineElement(mark);
1309:                                mark.lineElemRef = elem;
1310:
1311:                                try {
1312:                                    op.insertMark(mark, startPos);
1313:                                } catch (InvalidMarkException e) {
1314:                                    if (Boolean
1315:                                            .getBoolean("netbeans.debug.exceptions")) { // NOI18N
1316:                                        e.printStackTrace();
1317:                                    }
1318:                                }
1319:                            }
1320:
1321:                        }
1322:
1323:                        return elem;
1324:
1325:                    } catch (BadLocationException e) {
1326:                        if (Boolean.getBoolean("netbeans.debug.exceptions")) { // NOI18N
1327:                            e.printStackTrace();
1328:                        }
1329:                        return null;
1330:                    }
1331:                }
1332:
1333:                public boolean isLeaf() {
1334:                    return false;
1335:                }
1336:
1337:            }
1338:
1339:            /** Line element representation */
1340:            class LineElement implements  Element {
1341:
1342:                /** Mark at the begining of the line */
1343:                MarkFactory.LineMark startMark;
1344:
1345:                LineElement(MarkFactory.LineMark startMark)
1346:                        throws BadLocationException {
1347:                    this .startMark = startMark;
1348:                }
1349:
1350:                public Document getDocument() {
1351:                    return BaseDocument.this ;
1352:                }
1353:
1354:                public int getStartOffset() {
1355:                    try {
1356:                        return startMark.getOffset();
1357:                    } catch (InvalidMarkException e) {
1358:                        return 0;
1359:                    }
1360:                }
1361:
1362:                public int getEndOffset() {
1363:                    try {
1364:                        return op.getEOLNL(getStartOffset());
1365:                    } catch (BadLocationException e) {
1366:                        return 0;
1367:                    }
1368:                }
1369:
1370:                public Element getParentElement() {
1371:                    return lineRootElement;
1372:                }
1373:
1374:                public String getName() {
1375:                    return "line-element"; // NOI18N
1376:                }
1377:
1378:                public AttributeSet getAttributes() {
1379:                    return null;
1380:                }
1381:
1382:                public int getElementIndex(int offset) {
1383:                    return 0;
1384:                }
1385:
1386:                public int getElementCount() {
1387:                    return 0;
1388:                }
1389:
1390:                public Element getElement(int index) {
1391:                    return null;
1392:                }
1393:
1394:                public boolean isLeaf() {
1395:                    return true;
1396:                }
1397:
1398:                public void finalize() throws Throwable {
1399:                    try {
1400:                        startMark.remove();
1401:                    } catch (InvalidMarkException e) {
1402:                    }
1403:                    super .finalize();
1404:                }
1405:
1406:                public String toString() {
1407:                    return "getStartOffset()=" + getStartOffset() // NOI18N
1408:                            + ", getEndOffset()=" + getEndOffset() // NOI18N
1409:                            + ", getParentElement()=" + getParentElement(); // NOI18N
1410:                }
1411:
1412:            }
1413:
1414:            /**
1415:             * Compound edit that write-locks the document for the whole processing of
1416:             * its undo operation.
1417:             */
1418:            class AtomicCompoundEdit extends CompoundEdit {
1419:
1420:                public void undo() throws CannotUndoException {
1421:                    extWriteLock();
1422:                    try {
1423:                        super .undo();
1424:                    } finally {
1425:                        extWriteUnlock();
1426:                    }
1427:                }
1428:
1429:                public void redo() throws CannotRedoException {
1430:                    extWriteLock();
1431:                    try {
1432:                        super .redo();
1433:                    } finally {
1434:                        extWriteUnlock();
1435:                    }
1436:                }
1437:
1438:            }
1439:
1440:            /**
1441:             * Property evaluator is useful for lazy evaluation of properties of the
1442:             * document when
1443:             * {@link javax.swing.text.Document#getProperty(java.lang.String)} is
1444:             * called.
1445:             */
1446:            public interface PropertyEvaluator {
1447:
1448:                /** Get the real value of the property */
1449:                public Object getValue();
1450:
1451:            }
1452:
1453:            private class LazyPropertyMap extends Hashtable {
1454:
1455:                LazyPropertyMap(Dictionary dict) {
1456:                    super (5);
1457:
1458:                    Enumeration en = dict.keys();
1459:                    while (en.hasMoreElements()) {
1460:                        Object key = en.nextElement();
1461:                        put(key, dict.get(key));
1462:                    }
1463:                }
1464:
1465:                public Object get(Object key) {
1466:                    Object val = super .get(key);
1467:                    if (val instanceof  PropertyEvaluator) {
1468:                        val = ((PropertyEvaluator) val).getValue();
1469:                    }
1470:
1471:                    return val;
1472:                }
1473:
1474:            }
1475:
1476:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.