Source Code Cross Referenced for DefinitionsDocument.java in  » IDE » DrJava » edu » rice » cs » drjava » model » definitions » 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 » IDE » DrJava » edu.rice.cs.drjava.model.definitions 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*BEGIN_COPYRIGHT_BLOCK
0002:         *
0003:         * Copyright (c) 2001-2007, JavaPLT group at Rice University (javaplt@rice.edu)
0004:         * All rights reserved.
0005:         * 
0006:         * Redistribution and use in source and binary forms, with or without
0007:         * modification, are permitted provided that the following conditions are met:
0008:         *    * Redistributions of source code must retain the above copyright
0009:         *      notice, this list of conditions and the following disclaimer.
0010:         *    * Redistributions in binary form must reproduce the above copyright
0011:         *      notice, this list of conditions and the following disclaimer in the
0012:         *      documentation and/or other materials provided with the distribution.
0013:         *    * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
0014:         *      names of its contributors may be used to endorse or promote products
0015:         *      derived from this software without specific prior written permission.
0016:         * 
0017:         * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
0018:         * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
0019:         * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
0020:         * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
0021:         * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0022:         * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
0023:         * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
0024:         * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
0025:         * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
0026:         * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
0027:         * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0028:         *
0029:         * This software is Open Source Initiative approved Open Source Software.
0030:         * Open Source Initative Approved is a trademark of the Open Source Initiative.
0031:         * 
0032:         * This file is part of DrJava.  Download the current version of this project
0033:         * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
0034:         * 
0035:         * END_COPYRIGHT_BLOCK*/
0036:
0037:        package edu.rice.cs.drjava.model.definitions;
0038:
0039:        import javax.swing.text.*;
0040:        import javax.swing.undo.*;
0041:        import javax.swing.event.DocumentEvent;
0042:        import java.util.LinkedList;
0043:        import java.util.List;
0044:        import java.util.Map;
0045:        import java.util.WeakHashMap;
0046:        import java.lang.ref.WeakReference;
0047:
0048:        import java.io.File;
0049:        import java.io.Reader;
0050:        import java.io.StringReader;
0051:        import java.io.IOException;
0052:
0053:        import edu.rice.cs.drjava.model.definitions.reducedmodel.*;
0054:        import koala.dynamicjava.parser.Parser;
0055:        import koala.dynamicjava.parser.ParseException;
0056:        import edu.rice.cs.util.Log;
0057:        import edu.rice.cs.util.UnexpectedException;
0058:        import edu.rice.cs.util.swing.Utilities;
0059:        import edu.rice.cs.drjava.model.definitions.indent.Indenter;
0060:        import edu.rice.cs.drjava.model.OpenDefinitionsDocument;
0061:        import edu.rice.cs.drjava.model.*;
0062:
0063:        /** The document model for the definitions pane.
0064:         *
0065:         *  This implementation of <code>Document</code> contains a "reduced model". The reduced model is automatically kept
0066:         *  in sync when this document is updated. Also, that synchronization is maintained even across undo/redo -- this is 
0067:         *  done by making the undo/redo commands know how to restore the reduced model state.
0068:         *
0069:         *  The reduced model is not thread-safe, so it is essential that ONLY this DefinitionsDocument call methods on it.  
0070:         *  Any information from the reduced model should be obtained through helper methods on DefinitionsDocument, and ALL 
0071:         *  methods in DefinitionsDocument which reference the reduced model (via the _reduced field) MUST be synchronized.  
0072:         *  This prevents any thread from seeing an inconsistent state in the middle of another thread's changes.
0073:         *
0074:         *  @see BraceReduction
0075:         *  @see ReducedModelControl
0076:         *  @see ReducedModelComment
0077:         *  @see ReducedModelBrace
0078:         */
0079:        public class DefinitionsDocument extends AbstractDJDocument implements 
0080:                Finalizable<DefinitionsDocument> {
0081:
0082:            public static final Log _log = new Log("GlobalModel.txt", false);
0083:            private static final int NO_COMMENT_OFFSET = 0;
0084:            private static final int WING_COMMENT_OFFSET = 2;
0085:
0086:            private volatile List<DocumentClosedListener> _closedListeners = new LinkedList<DocumentClosedListener>();
0087:
0088:            public void addDocumentClosedListener(DocumentClosedListener l) {
0089:                synchronized (_closedListeners) {
0090:                    _closedListeners.add(l);
0091:                }
0092:            }
0093:
0094:            public void removeDocumentClosedListener(DocumentClosedListener l) {
0095:                synchronized (_closedListeners) {
0096:                    _closedListeners.remove(l);
0097:                }
0098:            }
0099:
0100:            // begin debug code
0101:
0102:            //  private boolean _closed = false;
0103:            //  
0104:            //  protected void throwErrorHuh() {
0105:            //    if (_closed) throw new RuntimeException("Definitions Document is closed, yet is being used");
0106:            //  }
0107:
0108:            /** Called when this is kicked out of the document cache so that the references made to it may 
0109:             *  be released so that this can be GC'd. */
0110:            public void close() {
0111:                _removeIndenter();
0112:                synchronized (_closedListeners) {
0113:                    for (DocumentClosedListener l : _closedListeners) {
0114:                        l.close();
0115:                    }
0116:                    _closedListeners = new LinkedList<DocumentClosedListener>();
0117:                }
0118:            }
0119:
0120:            // end debug code
0121:
0122:            /** The maximum number of undos the model can remember */
0123:            private static final int UNDO_LIMIT = 1000;
0124:            /** Specifies if tabs are removed on open and converted to spaces. */
0125:            private static boolean _tabsRemoved = true;
0126:            /** Specifies if the document has been modified since the last save. */
0127:            private volatile boolean _isModifiedSinceSave = false;
0128:            /** Cached location, aides in determining line number. */
0129:            private volatile int _cachedLocation;
0130:            /** Cached current line number. */
0131:            private volatile int _cachedLineNum;
0132:            /** Cached location of previous line. */
0133:            private volatile int _cachedPrevLineLoc;
0134:            /** Cached location of next line. */
0135:            private volatile int _cachedNextLineLoc;
0136:
0137:            /** This reference to the OpenDefinitionsDocument is needed so that the document iterator 
0138:             * (the DefaultGlobalModel) can find the next ODD given a DD. */
0139:            private volatile OpenDefinitionsDocument _odd;
0140:
0141:            private volatile CompoundUndoManager _undoManager;
0142:
0143:            /** Keeps track of the listeners to this model. */
0144:            private final GlobalEventNotifier _notifier;
0145:
0146:            /* Relying on the following definition in AbstractDJDocument.  It must be placed there to be initialized before use!
0147:            protected static final Object _wrappedPosListLock = new Object();
0148:             */
0149:
0150:            /** List with weak references to positions. */
0151:            private volatile LinkedList<WeakReference<WrappedPosition>> _wrappedPosList;
0152:
0153:            /** Convenience constructor for using a custom indenter.
0154:             *  @param indenter custom indenter class
0155:             *  @param notifier used by CompoundUndoManager to announce undoable edits
0156:             */
0157:            public DefinitionsDocument(Indenter indenter,
0158:                    GlobalEventNotifier notifier) {
0159:                super (indenter);
0160:                _notifier = notifier;
0161:                _init();
0162:                resetUndoManager();
0163:            }
0164:
0165:            /** Main constructor.  This has an obnoxious dependency on GlobalEventNotifier, which is passed through here only 
0166:             *  for a single usage in CompoundUndoManager.  TODO: find a better way.
0167:             *  @param notifier used by CompoundUndoManager to announce undoable edits
0168:             */
0169:            public DefinitionsDocument(GlobalEventNotifier notifier) {
0170:                super ();
0171:                _notifier = notifier;
0172:                _init();
0173:                resetUndoManager();
0174:            }
0175:
0176:            /** Main constructor.  This has an obnoxious dependency on GlobalEventNotifier, which is passed through here only 
0177:             *  for a single usage in CompoundUndoManager.  TODO: find a better way.
0178:             *  @param notifier used by CompoundUndoManager to announce undoable edits
0179:             */
0180:            public DefinitionsDocument(GlobalEventNotifier notifier,
0181:                    CompoundUndoManager undoManager) {
0182:                super ();
0183:                _notifier = notifier;
0184:                _init();
0185:                _undoManager = undoManager;
0186:            }
0187:
0188:            //  public void setUndoManager(CompoundUndoManager undoManager) {
0189:            //    if (undoManager != null)
0190:            //      _undoManager = undoManager;
0191:            //  }
0192:
0193:            /** Returns a new indenter. */
0194:            protected Indenter makeNewIndenter(int indentLevel) {
0195:                return new Indenter(indentLevel);
0196:            }
0197:
0198:            /** Private common helper for constructors. */
0199:            private void _init() {
0200:                _odd = null;
0201:                _cachedLocation = 0;
0202:                _cachedLineNum = 1;
0203:                _cachedPrevLineLoc = -1;
0204:                _cachedNextLineLoc = -1;
0205:                _cacheInUse = false;
0206:            }
0207:
0208:            /* acquireReadLock, releaseReadLock, acquireWriteLock, releaseWriteLock are inherited from AbstractDJDocument. */
0209:
0210:            /** Sets the OpenDefinitionsDocument that holds this DefinitionsDocument (the odd can only be set once).
0211:             *  @param odd the OpenDefinitionsDocument to set as this DD's holder
0212:             */
0213:            public void setOpenDefDoc(OpenDefinitionsDocument odd) {
0214:                if (_odd == null)
0215:                    _odd = odd;
0216:            }
0217:
0218:            /** @return the OpenDefinitonsDocument that is associated with this DefinitionsDocument. */
0219:            public OpenDefinitionsDocument getOpenDefDoc() {
0220:                if (_odd == null)
0221:                    throw new IllegalStateException(
0222:                            "The OpenDefinitionsDocument for this DefinitionsDocument has never been set");
0223:                else
0224:                    return _odd;
0225:            }
0226:
0227:            protected void _styleChanged() {
0228:                acquireWriteLock();
0229:                try {
0230:                    int length = getLength() - _currentLocation;
0231:
0232:                    //DrJava.consoleErr().println("Changed: " + _currentLocation + ", " + length);
0233:                    DocumentEvent evt = new DefaultDocumentEvent(
0234:                            _currentLocation, length,
0235:                            DocumentEvent.EventType.CHANGE);
0236:                    fireChangedUpdate(evt);
0237:                } finally {
0238:                    releaseWriteLock();
0239:                }
0240:            }
0241:
0242:            /**
0243:             * Returns whether this document is currently untitled
0244:             * (indicating whether it has a file yet or not).
0245:             * @return true if the document is untitled and has no file
0246:             */
0247:            //  public boolean isUntitled() {
0248:            //    return (_file == null);
0249:            //  }
0250:            /**
0251:             * Returns the file for this document.  If the document
0252:             * is untitled and has no file, it throws an IllegalStateException.
0253:             * @return the file for this document
0254:             * @throws IllegalStateException if file has not been set
0255:             * @throws FileMovedException if file has been moved or deleted from its previous location
0256:             */
0257:            //  public File getFilex()
0258:            //    throws IllegalStateException , FileMovedException {
0259:            //    if (_file == null) {
0260:            //      throw new IllegalStateException(
0261:            //        "This document does not yet have a file.");
0262:            //    }
0263:            //    //does the file actually exist?
0264:            //    if (_file.exists()) {
0265:            //      return _file;
0266:            //    }
0267:            //    else {
0268:            //      throw new FileMovedException(_file,
0269:            //        "This document's file has been moved or deleted.");
0270:            //    }
0271:            //  }
0272:            //
0273:            //  /**
0274:            //   * Returns the name of this file, or "(untitled)" if no file.
0275:            //   */
0276:            //  public String getFilenamex() {
0277:            //    String filename = "(Untitled)";
0278:            //    try {
0279:            //      File file = getFilex();
0280:            //      filename = file.getName();
0281:            //    }
0282:            //    catch (IllegalStateException ise) {
0283:            //      // No file, leave as "untitled"
0284:            //    }
0285:            //    catch (FileMovedException fme) {
0286:            //      // Recover, even though file has been deleted
0287:            //      File file = fme.getFile();
0288:            //      filename = file.getName();
0289:            //    }
0290:            //    return filename;
0291:            //  }
0292:
0293:            //  public void setFile(File file) {
0294:            //    _file = file;
0295:            //
0296:            //    //jim: maybe need lock
0297:            //    if (_file != null) {
0298:            //      _timestamp = _file.lastModified();
0299:            //    }
0300:            //  }
0301:            //
0302:            //  public long getTimestamp() {
0303:            //    return _timestamp;
0304:            //  }
0305:
0306:            /** Gets the package and main class/interface name of this OpenDefinitionsDocument
0307:             *  @return the qualified main class/interface name
0308:             */
0309:            public String getQualifiedClassName()
0310:                    throws ClassNameNotFoundException {
0311:                return _getPackageQualifier() + getMainClassName();
0312:            }
0313:
0314:            /** Gets fully qualified class name of the top level class enclosing the given position. */
0315:            public String getQualifiedClassName(int pos)
0316:                    throws ClassNameNotFoundException {
0317:                return _getPackageQualifier()
0318:                        + getEnclosingTopLevelClassName(pos);
0319:            }
0320:
0321:            /** Gets an appropriate prefix to fully qualify a class name. Returns this class's package followed by a dot, or the
0322:             *  empty string if no package name is found.
0323:             */
0324:            protected String _getPackageQualifier() {
0325:                String packageName = getPackageName();
0326:                if ((packageName != null) && (!packageName.equals(""))) {
0327:                    packageName = packageName + ".";
0328:                }
0329:                return packageName;
0330:            }
0331:
0332:            /** Inserts a string of text into the document.  This is not where we do custom processing of the insert; that is
0333:             *  done in {@link #insertUpdate}.
0334:             */
0335:            public void insertString(int offset, String str, AttributeSet a)
0336:                    throws BadLocationException {
0337:
0338:                // If _removeTabs is set to true, remove all tabs from str.
0339:                // It is a current invariant of the tabification functionality that
0340:                // the document contains no tabs, but we want to allow the user
0341:                // to override this functionality.
0342:
0343:                acquireWriteLock();
0344:                try {
0345:                    if (_tabsRemoved)
0346:                        str = _removeTabs(str);
0347:                    setModifiedSinceSave();
0348:                    super .insertString(offset, str, a);
0349:                } finally {
0350:                    releaseWriteLock();
0351:                }
0352:            }
0353:
0354:            /** Removes a block of text from the specified location. We don't update the reduced model here; that happens
0355:             *  in {@link #removeUpdate}.
0356:             */
0357:            public void remove(int offset, int len) throws BadLocationException {
0358:
0359:                if (len == 0)
0360:                    return;
0361:
0362:                acquireWriteLock();
0363:                try {
0364:                    setModifiedSinceSave();
0365:                    super .remove(offset, len);
0366:                } finally {
0367:                    releaseWriteLock();
0368:                }
0369:            }
0370:
0371:            /** Given a String, return a new String will all tabs converted to spaces.  Each tab is converted 
0372:             *  to one space, since changing the number of characters within insertString screws things up.
0373:             *  @param source the String to be converted.
0374:             *  @return a String will all the tabs converted to spaces
0375:             */
0376:            static String _removeTabs(final String source) {
0377:                //    clearCache(); // Clear the helper method cache  // Goofy code! Eliminated when method was converted to static.
0378:                return source.replace('\t', ' ');
0379:            }
0380:
0381:            /** Resets the modification state of this document to be consistent with state of _undoManager.  Called whenever
0382:             *  an undo or redo is performed. */
0383:            public void updateModifiedSinceSave() {
0384:
0385:                acquireWriteLock();
0386:                try {
0387:                    _isModifiedSinceSave = _undoManager.isModified();
0388:                    //    System.out.println("DefinitionsDocument: set modified? " + _modifiedSinceSave);
0389:                } finally {
0390:                    if (!_isModifiedSinceSave && _odd != null)
0391:                        _odd.documentReset();
0392:                    releaseWriteLock();
0393:                    //    Utilities.showDebug("DefintionsDocument: _modifiedSinceSave = " + _modifiedSinceSave);
0394:                }
0395:            }
0396:
0397:            /** Sets the modification state of this document to true and updates the state of the associated _odd. 
0398:             *  Assumes that write lock is already held. */
0399:            private void setModifiedSinceSave() {
0400:                if (!_isModifiedSinceSave) {
0401:                    _isModifiedSinceSave = true;
0402:                    if (_odd != null)
0403:                        _odd.documentModified();
0404:                }
0405:            }
0406:
0407:            /** Resets the modification state of this document.  Used after a document has been saved or reverted. */
0408:            public void resetModification() {
0409:                acquireWriteLock();
0410:                try {
0411:                    _isModifiedSinceSave = false;
0412:                    _undoManager.documentSaved();
0413:                } finally {
0414:                    if (_odd != null)
0415:                        _odd.documentReset(); // null test required for some unit tests
0416:                    releaseWriteLock();
0417:
0418:                }
0419:            }
0420:
0421:            /** Determines if the document has been modified since the last save.
0422:             *  @return true if the document has been modified
0423:             */
0424:            public boolean isModifiedSinceSave() {
0425:                acquireReadLock();
0426:                try {
0427:                    return _isModifiedSinceSave;
0428:                } finally {
0429:                    releaseReadLock();
0430:                }
0431:            }
0432:
0433:            /** Return the current column of the cursor position. Uses a 0 based index. */
0434:            public int getCurrentCol() {
0435:                acquireReadLock();
0436:                try {
0437:                    Element root = getDefaultRootElement();
0438:                    int line = root.getElementIndex(_currentLocation);
0439:                    return _currentLocation
0440:                            - root.getElement(line).getStartOffset();
0441:                } finally {
0442:                    releaseReadLock();
0443:                }
0444:            }
0445:
0446:            /** Return the current line of the cursor position.  Uses a 1-based index. */
0447:            public int getCurrentLine() {
0448:                acquireReadLock();
0449:                try {
0450:                    return getDefaultRootElement().getElementIndex(
0451:                            _currentLocation) + 1;
0452:                } // line indices are 1-based
0453:                finally {
0454:                    releaseReadLock();
0455:                }
0456:            }
0457:
0458:            /** Returns the offset corresponding to the first character of the given line number,
0459:             *  or -1 if the lineNum is not found.  Avoid locking the document by copying its text.
0460:             *  @param lineNum the line number for which to calculate the offset.
0461:             *  @return the offset of the first character in the given line number
0462:             */
0463:            public int getOffset(int lineNum) {
0464:                if (lineNum < 0)
0465:                    return -1;
0466:                String defsText = getText();
0467:                int curLine = 1;
0468:                int offset = 0; // offset is number of chars from beginning of file
0469:
0470:                // offset is always pointing to the first character in a line
0471:                // at the top of the loop
0472:                while (offset < defsText.length()) {
0473:
0474:                    if (curLine == lineNum)
0475:                        return offset;
0476:
0477:                    int nextNewline = defsText.indexOf('\n', offset);
0478:                    if (nextNewline == -1)
0479:                        return -1; // end of the document, and couldn't find the supplied lineNum
0480:
0481:                    curLine++;
0482:                    offset = nextNewline + 1;
0483:                }
0484:                return -1;
0485:            }
0486:
0487:            /** Returns true iff tabs are to removed on text insertion. */
0488:            public boolean tabsRemoved() {
0489:                return _tabsRemoved;
0490:            }
0491:
0492:            /** Comments out all lines between selStart and selEnd, inclusive. The current cursor position is maintained 
0493:             *  after the operation.
0494:             *  @param selStart the document offset for the start of the selection
0495:             *  @param selEnd the document offset for the end of the selection
0496:             */
0497:            public int commentLines(int selStart, int selEnd) {
0498:
0499:                //int key = _undoManager.startCompoundEdit();  //Uncommented in regards to the FrenchKeyBoardFix
0500:                int toReturn = selEnd;
0501:                if (selStart == selEnd) {
0502:                    acquireWriteLock();
0503:                    try {
0504:                        synchronized (_reduced) {
0505:                            setCurrentLocation(selStart);
0506:                            Position oldCurrentPosition = createUnwrappedPosition(_currentLocation);
0507:                            _commentLine();
0508:                            toReturn += WING_COMMENT_OFFSET;
0509:                            //int caretPos = getCaretPosition();
0510:                            //_doc().setCurrentLocation(caretPos);
0511:                        }
0512:                    } catch (BadLocationException e) {
0513:                        throw new UnexpectedException(e);
0514:                    } finally {
0515:                        releaseWriteLock();
0516:                    }
0517:                } else
0518:                    toReturn = _commentBlock(selStart, selEnd);
0519:                _undoManager.endLastCompoundEdit(); //Changed from endCompoundEdit(key) for FrenchKeyBoardFix
0520:                return toReturn;
0521:            }
0522:
0523:            /** Comments out the lines between and including the lines containing points start and end, using wing 
0524:             *  comments -- "// ".
0525:             * 
0526:             *  @param start Position in document to start commenting from
0527:             *  @param end Position in document to end commenting at
0528:             */
0529:            private int _commentBlock(final int start, final int end) {
0530:                int afterCommentEnd = end;
0531:                acquireWriteLock();
0532:                try {
0533:                    // Keep marker at the end. This Position will be the correct endpoint no matter how we change the doc doing the
0534:                    // indentLine calls.
0535:                    final Position endPos = this .createUnwrappedPosition(end);
0536:                    // Iterate, line by line, until we get to/past the end
0537:                    int walker = start;
0538:                    synchronized (_reduced) {
0539:                        while (walker < endPos.getOffset()) {
0540:                            setCurrentLocation(walker);
0541:                            // Keep pointer to walker position that will stay current
0542:                            // regardless of how commentLine changes things
0543:                            Position walkerPos = this 
0544:                                    .createUnwrappedPosition(walker);
0545:                            // Comment out current line
0546:                            _commentLine(); // must be atomic
0547:                            afterCommentEnd += WING_COMMENT_OFFSET;
0548:                            // Move back to walker spot
0549:                            setCurrentLocation(walkerPos.getOffset());
0550:                            walker = walkerPos.getOffset();
0551:                            // Adding 1 makes us point to the first character AFTER the next newline.
0552:                            // We don't actually move yet. That happens at the top of the loop,
0553:                            // after we check if we're past the end.
0554:                            walker += _reduced.getDistToNextNewline() + 1;
0555:                            //DrJava.consoleOut().println("progress: " + (100*(walker-start)/(end-start)));
0556:                        }
0557:                    }
0558:                } catch (BadLocationException e) {
0559:                    throw new UnexpectedException(e);
0560:                } finally {
0561:                    releaseWriteLock();
0562:                }
0563:                return afterCommentEnd;
0564:            }
0565:
0566:            /** Comments out a single line with wing comments -- "// ". 
0567:             *  @pre this.writeLock() and _reduced lock are already held! */
0568:            private void _commentLine() {
0569:                // Insert "// " at the beginning of the line.
0570:                // Using null for AttributeSet follows convention in this class.
0571:                try {
0572:                    insertString(_currentLocation - getCurrentCol(), "//", null);
0573:                } catch (BadLocationException e) {
0574:                    throw new UnexpectedException(e);
0575:                }
0576:            }
0577:
0578:            /** Uncomments all lines between selStart and selEnd, inclusive.
0579:             *  The current cursor position is maintained after the operation.
0580:             *  @param selStart the document offset for the start of the selection
0581:             *  @param selEnd the document offset for the end of the selection
0582:             */
0583:            public int uncommentLines(int selStart, int selEnd) {
0584:
0585:                //int key = _undoManager.startCompoundEdit(); //commented out for FrenchKeyBoardFix
0586:                int toReturn = selEnd;
0587:                if (selStart == selEnd) {
0588:                    acquireWriteLock();
0589:                    try {
0590:                        synchronized (_reduced) {
0591:                            setCurrentLocation(selStart);
0592:                            Position oldCurrentPosition = createUnwrappedPosition(_currentLocation);
0593:                            _uncommentLine(); // accesses _reduced
0594:                            toReturn -= WING_COMMENT_OFFSET;
0595:                            //int caretPos = getCaretPosition();
0596:                            //_doc().setCurrentLocation(caretPos);
0597:                            //setCurrentLocation(oldCurrentPosition.getOffset());
0598:                        }
0599:                    } catch (BadLocationException e) {
0600:                        throw new UnexpectedException(e);
0601:                    } finally {
0602:                        releaseWriteLock();
0603:                    }
0604:                } else
0605:                    toReturn = _uncommentBlock(selStart, selEnd);
0606:                //_undoManager.endCompoundEdit(key); //Commented out for FrenchKeyBoardFix, Replaced with endLastCompoundEdit();
0607:                _undoManager.endLastCompoundEdit();
0608:                return toReturn;
0609:            }
0610:
0611:            /** Uncomments all lines between and including the lines containing
0612:             *  points start and end.  
0613:             * @param start Position in document to start commenting from
0614:             * @param end Position in document to end commenting at
0615:             */
0616:            private int _uncommentBlock(final int start, final int end) {
0617:                int afterUncommentEnd = end;
0618:                acquireWriteLock();
0619:                try {
0620:                    // Keep marker at the end. This Position will be the correct endpoint no matter how we change the doc
0621:                    // doing the indentLine calls.
0622:                    final Position endPos = this .createUnwrappedPosition(end);
0623:                    // Iterate, line by line, until we get to/past the end
0624:                    int walker = start;
0625:                    synchronized (_reduced) {
0626:                        while (walker < endPos.getOffset()) {
0627:                            setCurrentLocation(walker);
0628:                            // Keep pointer to walker position that will stay current
0629:                            // regardless of how commentLine changes things
0630:                            Position walkerPos = this 
0631:                                    .createUnwrappedPosition(walker);
0632:                            // uncomment current line
0633:                            afterUncommentEnd -= _uncommentLine(); // accesses _reduced
0634:                            // Move back to walker spot
0635:                            setCurrentLocation(walkerPos.getOffset());
0636:                            walker = walkerPos.getOffset();
0637:                            // Adding 1 makes us point to the first character AFTER the next newline.
0638:                            // We don't actually move yet. That happens at the top of the loop,
0639:                            // after we check if we're past the end.
0640:                            walker += _reduced.getDistToNextNewline() + 1;
0641:                            //DrJava.consoleOut().println("progress: " + (100*(walker-start)/(end-start)));
0642:                        }
0643:                    }
0644:                } catch (BadLocationException e) {
0645:                    throw new UnexpectedException(e);
0646:                } finally {
0647:                    releaseWriteLock();
0648:                }
0649:                return afterUncommentEnd;
0650:            }
0651:
0652:            /** Uncomments a single line.  This simply looks for a leading "//".  Assumes that _reduced lock is already held and
0653:             *  that acquireWriteLock is already held.
0654:             *  @pre theads hold this.writeLock() and _reduced lock
0655:             */
0656:            private int _uncommentLine() throws BadLocationException {
0657:                // Look for "//" at the beginning of the line, and remove it.
0658:                int curCol = getCurrentCol();
0659:                int lineStart = _currentLocation - curCol;
0660:                String text = getText(lineStart, curCol
0661:                        + _reduced.getDistToNextNewline());
0662:                int pos = text.indexOf("//");
0663:
0664:                //      System.out.println("" + _currentLocation + " " + curCol + " "
0665:                //                           + text + " " + pos + " " + _reduced.getDistToNextNewline());
0666:
0667:                // Look for any non-whitespace chars before the "//" on the line.
0668:                boolean goodWing = true;
0669:                for (int i = pos - 1; i >= 0; i--) {
0670:                    char c = text.charAt(i);
0671:                    // If a previous char is not whitespace, we're not looking at a wing comment.
0672:                    if (c != ' ') {
0673:                        goodWing = false;
0674:                        return NO_COMMENT_OFFSET;
0675:                    }
0676:                }
0677:
0678:                // If a wing comment wasn't found, or if the wings aren't the first
0679:                // non-whitespace characters on the line, do nothing.
0680:                if (pos >= 0 && goodWing) {
0681:                    // Otherwise, remove the wings.
0682:                    remove(lineStart + pos, 2);
0683:                    //_indentLine(Indenter.IndentReason.OTHER);
0684:                    return WING_COMMENT_OFFSET;
0685:                }
0686:                return NO_COMMENT_OFFSET;
0687:            }
0688:
0689:            /** Goes to a particular line in the document. */
0690:            public void gotoLine(int line) {
0691:
0692:                int dist;
0693:                if (line < 0)
0694:                    return;
0695:                int actualLine = 1;
0696:
0697:                acquireReadLock();
0698:                int len = getLength();
0699:                try {
0700:                    synchronized (_reduced) {
0701:                        setCurrentLocation(0);
0702:                        for (int i = 1; (i < line) && (_currentLocation < len); i++) {
0703:                            dist = _reduced.getDistToNextNewline();
0704:                            if (_currentLocation + dist < len)
0705:                                dist++;
0706:                            actualLine++;
0707:                            move(dist);
0708:                        }
0709:                        _cachedLineNum = actualLine;
0710:                        _cachedLocation = _currentLocation;
0711:                        _cachedPrevLineLoc = getLineStartPos(_currentLocation);
0712:                        _cachedNextLineLoc = getLineEndPos(_currentLocation);
0713:                    }
0714:                } finally {
0715:                    releaseReadLock();
0716:                }
0717:            }
0718:
0719:            private int _findNextOpenSquiggly(String text, int pos)
0720:                    throws BadLocationException {
0721:                // acquireReadLock assumed to be held,
0722:                int i;
0723:                int reducedPos = pos;
0724:
0725:                synchronized (_reduced) {
0726:                    final int origLocation = _currentLocation;
0727:                    // Move reduced model to location pos
0728:                    _reduced.move(pos - origLocation); // reduced model points to pos == reducedPos
0729:
0730:                    // Walk forward from specificed position
0731:                    i = text.indexOf('{', reducedPos);
0732:                    while (i > -1) {
0733:                        // Move reduced model to walker's location
0734:                        _reduced.move(i - reducedPos); // reduced model points to i
0735:                        reducedPos = i; // reduced model points to reducedPos
0736:
0737:                        // Check if matching keyword should be ignored because it is within a comment, or quotes
0738:                        ReducedModelState state = _reduced.getStateAtCurrent();
0739:                        if (!state.equals(ReducedModelState.FREE)
0740:                                || _isStartOfComment(text, i)
0741:                                || ((i > 0) && _isStartOfComment(text, i - 1))) {
0742:                            i = text.indexOf('{', reducedPos + 1);
0743:                            continue; // ignore matching brace
0744:                        } else {
0745:                            break; // found our brace
0746:                        }
0747:                    } // end synchronized
0748:
0749:                    _reduced.move(origLocation - reducedPos); // Restore the state of the reduced model;
0750:                }
0751:
0752:                if (i == -1)
0753:                    reducedPos = ERROR_INDEX; // No matching brace was found
0754:                return reducedPos;
0755:            }
0756:
0757:            private int _findPrevKeyword(String text, String kw, int pos)
0758:                    throws BadLocationException {
0759:                // acquireReadLock assumed to be held,
0760:                int i;
0761:                int reducedPos = pos;
0762:
0763:                synchronized (_reduced) {
0764:                    final int origLocation = _currentLocation;
0765:                    // Move reduced model to location pos
0766:                    _reduced.move(pos - origLocation); // reduced model points to pos == reducedPos
0767:
0768:                    // Walk backwards from specificed position
0769:                    i = text.lastIndexOf(kw, reducedPos);
0770:                    while (i > -1) {
0771:                        // Check that this is the beginning of a word
0772:                        if (i > 0) {
0773:                            if (Character.isJavaIdentifierPart(text
0774:                                    .charAt(i - 1))) {
0775:                                // not begining
0776:                                i = text.lastIndexOf(kw, i - 1);
0777:                                continue; // ignore matching keyword 
0778:                            }
0779:                        }
0780:                        // Check that this not just the beginning of a longer word
0781:                        if (i + kw.length() < text.length()) {
0782:                            if (Character.isJavaIdentifierPart(text.charAt(i
0783:                                    + kw.length()))) {
0784:                                // not begining
0785:                                i = text.lastIndexOf(kw, i - 1);
0786:                                continue; // ignore matching keyword 
0787:                            }
0788:                        }
0789:
0790:                        // Move reduced model to walker's location
0791:                        _reduced.move(i - reducedPos); // reduced model points to i
0792:                        reducedPos = i; // reduced model points to reducedPos
0793:
0794:                        // Check if matching keyword should be ignored because it is within a comment, or quotes
0795:                        ReducedModelState state = _reduced.getStateAtCurrent();
0796:                        if (!state.equals(ReducedModelState.FREE)
0797:                                || _isStartOfComment(text, i)
0798:                                || ((i > 0) && _isStartOfComment(text, i - 1))) {
0799:                            i = text.lastIndexOf(kw, reducedPos - 1);
0800:                            continue; // ignore matching keyword 
0801:                        } else {
0802:                            break; // found our keyword
0803:                        }
0804:                    } // end synchronized/
0805:
0806:                    _reduced.move(origLocation - reducedPos); // Restore the state of the reduced model;
0807:                }
0808:
0809:                if (i == -1)
0810:                    reducedPos = ERROR_INDEX; // No matching keyword was found
0811:                return reducedPos;
0812:            }
0813:
0814:            //  public static boolean log = true;
0815:
0816:            /** Searching backwards finds the name of the enclosing named class or interface. NB: ignores comments.
0817:             *  WARNING: In long source files and when contained in anonymous inner classes, this function might take a LONG time.
0818:             * @param pos Position to start from
0819:             * @param qual true to find the fully qualified class name
0820:             * @return name of the enclosing named class or interface
0821:             */
0822:            public String getEnclosingClassName(int pos, boolean qual)
0823:                    throws BadLocationException, ClassNameNotFoundException {
0824:                //    boolean oldLog = log; log = false;
0825:                // Check cache
0826:                final StringBuilder keyBuf = new StringBuilder(
0827:                        "getEnclosingClassName:").append(pos);
0828:                keyBuf.append(":").append(qual);
0829:                String key = keyBuf.toString();
0830:                String cached = (String) _checkCache(key);
0831:                if (cached != null)
0832:                    return cached;
0833:
0834:                char[] delims = { '{', '}', '(', ')', '[', ']', '+', '-', '/',
0835:                        '*', ';', ':', '=', '!', '@', '#', '$', '%', '^', '~',
0836:                        '\\', '"', '`', '|' };
0837:                String name = "";
0838:
0839:                acquireReadLock();
0840:                try {
0841:                    String text = getText(DOCSTART, pos + 1);
0842:
0843:                    int curPos = pos;
0844:
0845:                    do {
0846:                        if ((text.charAt(curPos) != '{')
0847:                                || (text.charAt(curPos) != '}')) {
0848:                            ++curPos;
0849:                        }
0850:
0851:                        //        if (oldLog) System.out.println("curPos=" + curPos + " `" +
0852:                        //                                       text.substring(Math.max(0,curPos-10), Math.min(text.length(), curPos+1)) + "`");
0853:
0854:                        curPos = findPrevEnclosingBrace(curPos, '{', '}');
0855:                        if (curPos == ERROR_INDEX) {
0856:                            break;
0857:                        }
0858:                        int classPos = _findPrevKeyword(text, "class", curPos);
0859:                        int interPos = _findPrevKeyword(text, "interface",
0860:                                curPos);
0861:                        int otherPos = findPrevDelimiter(curPos, delims);
0862:                        int newPos = ERROR_INDEX;
0863:                        // see if there's a ) closer by
0864:                        int closeParenPos = findPrevNonWSCharPos(curPos);
0865:                        if ((closeParenPos != ERROR_INDEX)
0866:                                && (text.charAt(closeParenPos) == ')')) {
0867:                            // yes, find the matching (
0868:                            int openParenPos = findPrevEnclosingBrace(
0869:                                    closeParenPos, '(', ')');
0870:                            if ((openParenPos != ERROR_INDEX)
0871:                                    && (text.charAt(openParenPos) == '(')) {
0872:                                // this might be an inner class
0873:                                newPos = _findPrevKeyword(text, "new",
0874:                                        openParenPos);
0875:                                //            if (oldLog) System.out.println("\tnew found at "+newPos+", openSquigglyPos="+curPos);
0876:                                if (!_isAnonymousInnerClass(newPos, curPos)) {
0877:                                    // not an anonymous inner class
0878:                                    newPos = ERROR_INDEX;
0879:                                }
0880:                            }
0881:                        }
0882:                        //        if (oldLog) System.out.println("curPos="+curPos+" `"+text.substring(Math.max(0,curPos-10),curPos+1)+"`");
0883:                        //        if (oldLog) System.out.println("\tclass="+classPos+", inter="+interPos+", other="+otherPos+", new="+newPos+" `" +
0884:                        //          text.substring(Math.max(0,otherPos-10),otherPos+1)+"`");
0885:                        while ((classPos != ERROR_INDEX)
0886:                                || (interPos != ERROR_INDEX)
0887:                                || (newPos != ERROR_INDEX)) {
0888:                            if (newPos != ERROR_INDEX) {
0889:                                //            if (oldLog) System.out.println("\tanonymous inner class! newPos = "+newPos);
0890:                                classPos = ERROR_INDEX;
0891:                                interPos = ERROR_INDEX;
0892:                                break;
0893:                            } else if ((otherPos > classPos)
0894:                                    && (otherPos > interPos)) {
0895:                                if ((text.charAt(otherPos) != '{')
0896:                                        || (text.charAt(otherPos) != '}')) {
0897:                                    ++otherPos;
0898:                                }
0899:                                curPos = findPrevEnclosingBrace(otherPos, '{',
0900:                                        '}');
0901:                                classPos = _findPrevKeyword(text, "class",
0902:                                        curPos);
0903:                                interPos = _findPrevKeyword(text, "interface",
0904:                                        curPos);
0905:                                otherPos = findPrevDelimiter(curPos, delims);
0906:                                newPos = ERROR_INDEX;
0907:                                // see if there's a ) closer by
0908:                                closeParenPos = findPrevNonWSCharPos(curPos);
0909:                                //            if (closeParenPos!=ERROR_INDEX) if (oldLog) System.out.println("nonWS before curPos = " + closeParenPos + 
0910:                                //              " `"+text.charAt(closeParenPos)+"`");
0911:                                if ((closeParenPos != ERROR_INDEX)
0912:                                        && (text.charAt(closeParenPos) == ')')) {
0913:                                    // yes, find the matching (
0914:                                    int openParenPos = findPrevEnclosingBrace(
0915:                                            closeParenPos, '(', ')');
0916:                                    if ((openParenPos != ERROR_INDEX)
0917:                                            && (text.charAt(openParenPos) == '(')) {
0918:                                        // this might be an inner class
0919:                                        newPos = _findPrevKeyword(text, "new",
0920:                                                openParenPos);
0921:                                        //                if (oldLog) System.out.println("\tnew found at " + newPos + ", openSquigglyPos=" + curPos);
0922:                                        if (_isAnonymousInnerClass(newPos,
0923:                                                curPos)) {
0924:                                            // yes, anonymous inner class
0925:                                        } else {
0926:                                            newPos = ERROR_INDEX;
0927:                                        }
0928:                                    }
0929:                                }
0930:                                //            if (oldLog) System.out.println("curPos=" +curPos+" `"+text.substring(Math.max(0,curPos-10),curPos+1)+"`");
0931:                                //            if (oldLog) System.out.println("\tclass="+classPos+", inter="+interPos+", other="+otherPos+" `"+
0932:                                //              text.substring(Math.max(0,otherPos-10),otherPos+1)+"`");
0933:                            } else {
0934:                                // either class or interface found first            
0935:                                curPos = Math.max(classPos, Math.max(interPos,
0936:                                        newPos));
0937:                                break;
0938:                            }
0939:                        }
0940:
0941:                        if ((classPos != ERROR_INDEX)
0942:                                || (interPos != ERROR_INDEX)) {
0943:                            if (classPos > interPos) {
0944:                                // class found first
0945:                                curPos += "class".length();
0946:                            } else {
0947:                                // interface found first
0948:                                curPos += "interface".length();
0949:                            }
0950:                            int nameStart = getFirstNonWSCharPos(curPos);
0951:                            if (nameStart == ERROR_INDEX) {
0952:                                throw new ClassNameNotFoundException(
0953:                                        "Cannot determine enclosing class name");
0954:                            }
0955:                            int nameEnd = nameStart + 1;
0956:                            while (nameEnd < text.length()) {
0957:                                if ((!Character.isJavaIdentifierPart(text
0958:                                        .charAt(nameEnd)))
0959:                                        && (text.charAt(nameEnd) != '.')) {
0960:                                    // delimiter found
0961:                                    break;
0962:                                }
0963:                                ++nameEnd;
0964:                            }
0965:                            name = text.substring(nameStart, nameEnd) + '$'
0966:                                    + name;
0967:                        } else if (newPos != ERROR_INDEX) {
0968:                            name = String
0969:                                    .valueOf(_getAnonymousInnerClassIndex(curPos))
0970:                                    + "$" + name;
0971:                            curPos = newPos;
0972:                        } else {
0973:                            // neither class nor interface found
0974:                            break;
0975:                        }
0976:                    } while (qual);
0977:                } finally {
0978:                    releaseReadLock();
0979:                }
0980:
0981:                // chop off '$' at the end.
0982:                if (name.length() > 0)
0983:                    name = name.substring(0, name.length() - 1);
0984:
0985:                if (qual) {
0986:                    String pn = getPackageName();
0987:                    if ((pn.length() > 0) && (name.length() > 0)) {
0988:                        name = getPackageName() + "." + name;
0989:                    }
0990:                }
0991:                //    log = oldLog;
0992:                return name;
0993:            }
0994:
0995:            /** Returns true if this position is the instantiation of an anonymous inner class.
0996:             *  @param newPos position of "new"
0997:             *  @param openSquigglyPos position of the next '{'
0998:             *  @return true if anonymous inner class instantiation
0999:             */
1000:            private boolean _isAnonymousInnerClass(int newPos,
1001:                    int openSquigglyPos) throws BadLocationException {
1002:                //    String t = getText(DOCSTART, openSquigglyPos+1);
1003:                //    System.out.print ("_isAnonymousInnerClass("+newPos+", "+openSquigglyPos+")");
1004:                //    System.out.println("_isAnonymousInnerClass("+newPos+", "+openSquigglyPos+"): `"+
1005:                //                       t.substring(newPos, openSquigglyPos+1)+"`");
1006:
1007:                // Check cache
1008:                final StringBuilder keyBuf = new StringBuilder(
1009:                        "_getAnonymousInnerClassIndex:").append(newPos).append(
1010:                        ':').append(openSquigglyPos);
1011:                String key = keyBuf.toString();
1012:                Boolean cached = (Boolean) _checkCache(key);
1013:                if (cached != null) {
1014:                    //      System.out.println(" ==> "+cached);
1015:                    return cached;
1016:                }
1017:
1018:                // acquireReadLock assumed to be held
1019:                cached = false;
1020:                String text = getText(DOCSTART, openSquigglyPos + 1);
1021:                int origNewPos = newPos;
1022:                newPos += "new".length();
1023:                int classStart = getFirstNonWSCharPos(newPos);
1024:                if (classStart != ERROR_INDEX) {
1025:                    int classEnd = classStart + 1;
1026:                    while (classEnd < text.length()) {
1027:                        if ((!Character.isJavaIdentifierPart(text
1028:                                .charAt(classEnd)))
1029:                                && (text.charAt(classEnd) != '.')) {
1030:                            // delimiter found
1031:                            break;
1032:                        }
1033:                        ++classEnd;
1034:                    }
1035:                    // System.out.println("\tclass = `"+text.substring(classStart,classEnd)+"`");
1036:                    int parenStart = getFirstNonWSCharPos(classEnd);
1037:                    if (parenStart != ERROR_INDEX) {
1038:                        int origParenStart = parenStart;
1039:
1040:                        // System.out.println("\tfirst non-whitespace after class = "+parenStart+" `"+text.charAt(parenStart)+"`");
1041:                        if (text.charAt(origParenStart) == '<') {
1042:                            parenStart = ERROR_INDEX;
1043:                            // might be a generic class
1044:                            int closePointyBracket = findNextEnclosingBrace(
1045:                                    origParenStart, '<', '>');
1046:                            if (closePointyBracket != ERROR_INDEX) {
1047:                                if (text.charAt(closePointyBracket) == '>') {
1048:                                    parenStart = getFirstNonWSCharPos(closePointyBracket + 1);
1049:                                }
1050:                            }
1051:                        }
1052:                    }
1053:                    if (parenStart != ERROR_INDEX) {
1054:                        if (text.charAt(parenStart) == '(') {
1055:                            synchronized (_reduced) {
1056:                                final int origLocation = _currentLocation;
1057:                                _reduced.move(parenStart + 1 - origLocation); // reduced model points to pos == parenStart+1
1058:                                int parenEnd = balanceForward();
1059:                                _reduced.move(origLocation - (parenStart + 1)); // Restore the state of the reduced model;
1060:                                if (parenEnd > -1) {
1061:                                    parenEnd = parenEnd + parenStart + 1;
1062:                                    // System.out.println("\tafter closing paren = "+parenEnd);
1063:                                    int afterParen = getFirstNonWSCharPos(parenEnd);
1064:                                    // System.out.println("\tfirst non-whitespace after paren = "+parenStart+" `"+text.charAt(afterParen)+"`");
1065:                                    cached = (afterParen == openSquigglyPos);
1066:                                }
1067:                            }
1068:                        }
1069:                    }
1070:                }
1071:
1072:                _storeInCache(key, cached);
1073:
1074:                //    System.out.println(" ==> "+cached);
1075:                return cached;
1076:            }
1077:
1078:            /** Gets the package name embedded in the text of this document by minimally parsing the document to find the
1079:             *  package statement.  If package statement is not found or is ill-formed, returns "" as the package name.
1080:             *  @return The name of package embedded in this document.  If there is no well-formed package statement, 
1081:             *          returns "" as the package name.
1082:             */
1083:            public String getPackageName() {
1084:                Reader r;
1085:                acquireReadLock();
1086:                try {
1087:                    r = new StringReader(getText());
1088:                } finally {
1089:                    releaseReadLock();
1090:                }
1091:                try {
1092:                    return new Parser(r).packageDeclaration().getName();
1093:                } catch (ParseException e) {
1094:                    return "";
1095:                }
1096:                // addresses bug [ 1815387 ] Editor should discard parse errors for now
1097:                // we should upgrade our parser to handle @
1098:                catch (koala.dynamicjava.parser.TokenMgrError e) {
1099:                    return "";
1100:                } finally {
1101:                    try {
1102:                        r.close();
1103:                    } catch (IOException e) { /* ignore */
1104:                    }
1105:                }
1106:            }
1107:
1108:            /**
1109:             * Return the index of the anonymous inner class being instantiated at the specified position.
1110:             * @param position of the opening curly brace of the anonymous inner class
1111:             * @return anonymous class index
1112:             */
1113:            int _getAnonymousInnerClassIndex(int pos)
1114:                    throws BadLocationException, ClassNameNotFoundException {
1115:                //    boolean oldLog = log; log = false;
1116:
1117:                // Check cache
1118:                final StringBuilder keyBuf = new StringBuilder(
1119:                        "_getAnonymousInnerClassIndex:").append(pos);
1120:                final String key = keyBuf.toString();
1121:                final Integer cached = (Integer) _checkCache(key);
1122:                if (cached != null) {
1123:                    //      log = oldLog;
1124:                    return cached.intValue();
1125:                }
1126:
1127:                // acquireReadLock assumed to be held
1128:                --pos; // move outside the curly brace
1129:                char[] delims = { '{', '}', '(', ')', '[', ']', '+', '-', '/',
1130:                        '*', ';', ':', '=', '!', '@', '#', '$', '%', '^', '~',
1131:                        '\\', '"', '`', '|' };
1132:                String className = getEnclosingClassName(pos, true);
1133:                String text = getText(DOCSTART, pos);
1134:                int index = 1;
1135:                int newPos = pos;
1136:                //    if (oldLog) System.out.println("anon before "+pos+" enclosed by "+className);
1137:                while ((newPos = _findPrevKeyword(text, "new", newPos - 1)) != ERROR_INDEX) {
1138:                    //      if (oldLog) System.out.println("new found at "+newPos);
1139:                    int afterNewPos = newPos + "new".length();
1140:                    int classStart = getFirstNonWSCharPos(afterNewPos);
1141:                    if (classStart == ERROR_INDEX) {
1142:                        continue;
1143:                    }
1144:                    int classEnd = classStart + 1;
1145:                    while (classEnd < text.length()) {
1146:                        if ((!Character.isJavaIdentifierPart(text
1147:                                .charAt(classEnd)))
1148:                                && (text.charAt(classEnd) != '.')) {
1149:                            // delimiter found
1150:                            break;
1151:                        }
1152:                        ++classEnd;
1153:                    }
1154:                    //      if (oldLog) System.out.println("\tclass = `"+text.substring(classStart,classEnd)+"`");
1155:                    int parenStart = getFirstNonWSCharPos(classEnd);
1156:                    if (parenStart == ERROR_INDEX) {
1157:                        continue;
1158:                    }
1159:                    int origParenStart = parenStart;
1160:
1161:                    //      if (oldLog) System.out.println("\tfirst non-whitespace after class = "+parenStart+" `"+text.charAt(parenStart)+"`");
1162:                    if (text.charAt(origParenStart) == '<') {
1163:                        parenStart = ERROR_INDEX;
1164:                        // might be a generic class
1165:                        int closePointyBracket = findNextEnclosingBrace(
1166:                                origParenStart, '<', '>');
1167:                        if (closePointyBracket != ERROR_INDEX) {
1168:                            if (text.charAt(closePointyBracket) == '>') {
1169:                                parenStart = getFirstNonWSCharPos(closePointyBracket + 1);
1170:                            }
1171:                        }
1172:                    }
1173:                    if (parenStart == ERROR_INDEX) {
1174:                        continue;
1175:                    }
1176:                    if (text.charAt(parenStart) != '(') {
1177:                        continue;
1178:                    }
1179:                    int parenEnd = findNextEnclosingBrace(parenStart, '(', ')');
1180:
1181:                    int nextOpenSquiggly = _findNextOpenSquiggly(text, parenEnd);
1182:                    if (nextOpenSquiggly == ERROR_INDEX) {
1183:                        continue;
1184:                    }
1185:                    //      if (oldLog) System.out.println("{ found at "+nextOpenSquiggly+": `"+text.substring(newPos, nextOpenSquiggly+1)+"`");
1186:                    //      if (oldLog) System.out.println("_isAnonymousInnerClass("+newPos+", "+nextOpenSquiggly+")");
1187:                    if (_isAnonymousInnerClass(newPos, nextOpenSquiggly)) {
1188:                        //        if (oldLog) System.out.println("is anonymous inner class");
1189:                        String cn = getEnclosingClassName(newPos, true);
1190:                        //        if (oldLog) System.out.println("enclosing class = "+cn);
1191:                        if (!cn.startsWith(className)) {
1192:                            break;
1193:                        } else if (!cn.equals(className)) {
1194:                            newPos = findPrevEnclosingBrace(newPos, '{', '}');
1195:                            continue;
1196:                        } else {
1197:                            ++index;
1198:                        }
1199:                    }
1200:                }
1201:                _storeInCache(key, new Integer(index));
1202:                //    oldLog = log;
1203:                return index;
1204:            }
1205:
1206:            /** Returns the name of the class or interface enclosing the caret position at the top level.
1207:             *  @return Name of enclosing class or interface
1208:             *  @throws ClassNameNotFoundException if no enclosing class found
1209:             */
1210:            public String getEnclosingTopLevelClassName(int pos)
1211:                    throws ClassNameNotFoundException {
1212:                acquireReadLock();
1213:                synchronized (_reduced) {
1214:                    int oldLocation = _currentLocation;
1215:                    try {
1216:                        setCurrentLocation(pos);
1217:                        IndentInfo info = getIndentInformation();
1218:
1219:                        // Find top level open brace
1220:                        int topLevelBracePos = -1;
1221:                        String braceType = info.braceTypeCurrent;
1222:                        while (!braceType.equals(IndentInfo.noBrace)) {
1223:                            if (braceType.equals(IndentInfo.openSquiggly)) {
1224:                                topLevelBracePos = _currentLocation
1225:                                        - info.distToBraceCurrent;
1226:                            }
1227:                            move(-info.distToBraceCurrent);
1228:                            info = getIndentInformation();
1229:                            braceType = info.braceTypeCurrent;
1230:                        }
1231:                        if (topLevelBracePos == -1) {
1232:                            // No top level brace was found, so we can't find a top level class name
1233:                            setCurrentLocation(oldLocation);
1234:                            throw new ClassNameNotFoundException(
1235:                                    "no top level brace found");
1236:                        }
1237:
1238:                        char[] delims = { '{', '}', ';' };
1239:                        int prevDelimPos = findPrevDelimiter(topLevelBracePos,
1240:                                delims);
1241:                        if (prevDelimPos == ERROR_INDEX) {
1242:                            // Search from start of doc
1243:                            prevDelimPos = DOCSTART;
1244:                        } else
1245:                            prevDelimPos++;
1246:                        setCurrentLocation(oldLocation);
1247:
1248:                        // Parse out the class name
1249:                        return getNextTopLevelClassName(prevDelimPos,
1250:                                topLevelBracePos);
1251:                    } catch (BadLocationException ble) {
1252:                        throw new UnexpectedException(ble);
1253:                    } finally {
1254:                        setCurrentLocation(oldLocation);
1255:                        releaseReadLock();
1256:                    }
1257:                }
1258:            }
1259:
1260:            /** Gets the name of first class/interface decclared in file among the definitions anchored at:
1261:             * @param indexOfClass  index in this of a top-level occurrence of class 
1262:             * @param indexOfInterface  index in this of a top-level occurrence of interface
1263:             */
1264:            private String getFirstClassName(int indexOfClass,
1265:                    int indexOfInterface) throws ClassNameNotFoundException {
1266:
1267:                if ((indexOfClass == -1) && (indexOfInterface == -1))
1268:                    throw ClassNameNotFoundException.DEFAULT;
1269:                if ((indexOfInterface == -1)
1270:                        || (indexOfClass != -1 && indexOfClass < indexOfInterface))
1271:                    return getNextIdentifier(indexOfClass + "class".length());
1272:                return getNextIdentifier(indexOfInterface
1273:                        + "interface".length());
1274:            }
1275:
1276:            /** Gets the name of the document's main class: the document's only public class/interface or 
1277:             * first top level class if document contains no public classes or interfaces. */
1278:            public String getMainClassName() throws ClassNameNotFoundException {
1279:                acquireReadLock();
1280:                synchronized (_reduced) {
1281:                    final int oldLocation = _currentLocation;
1282:
1283:                    try {
1284:                        setCurrentLocation(0);
1285:                        final String text = getText();
1286:
1287:                        final int indexOfClass = _findKeywordAtToplevel(
1288:                                "class", text, 0);
1289:                        final int indexOfInterface = _findKeywordAtToplevel(
1290:                                "interface", text, 0);
1291:                        final int indexOfPublic = _findKeywordAtToplevel(
1292:                                "public", text, 0);
1293:
1294:                        if (indexOfPublic == -1)
1295:                            return getFirstClassName(indexOfClass,
1296:                                    indexOfInterface);
1297:
1298:                        //        _log.log("text =\n" + text);
1299:                        //        _log.log("indexOfClass = " + indexOfClass + "; indexOfPublic = " + indexOfPublic);
1300:
1301:                        // There is an explicit public declaration
1302:                        final int afterPublic = indexOfPublic
1303:                                + "public".length();
1304:                        final String subText = text.substring(afterPublic);
1305:                        setCurrentLocation(afterPublic);
1306:                        //        _log.log("After public text = '" + subText + "'");
1307:                        int indexOfPublicClass = _findKeywordAtToplevel(
1308:                                "class", subText, afterPublic); // relative offset
1309:                        if (indexOfPublicClass != -1)
1310:                            indexOfPublicClass += afterPublic;
1311:                        int indexOfPublicInterface = _findKeywordAtToplevel(
1312:                                "interface", subText, afterPublic); // relative offset
1313:                        if (indexOfPublicInterface != -1)
1314:                            indexOfPublicInterface += afterPublic;
1315:                        //        _log.log("indexOfPublicClass = " + indexOfPublicClass + " indexOfPublicInterface = " + indexOfPublicInterface);
1316:
1317:                        return getFirstClassName(indexOfPublicClass,
1318:                                indexOfPublicInterface);
1319:
1320:                    } finally {
1321:                        setCurrentLocation(oldLocation);
1322:                        releaseReadLock();
1323:                    }
1324:                }
1325:            }
1326:
1327:            /** Gets the name of the top level class in this source file. This attempts to find the first declaration
1328:             *  of a class or interface.
1329:             *   @return The name of first class in the file
1330:             * @throws ClassNameNotFoundException if no top level class found
1331:             */
1332:            public String getFirstTopLevelClassName()
1333:                    throws ClassNameNotFoundException {
1334:                return getNextTopLevelClassName(0, getLength());
1335:            }
1336:
1337:            // note: need to update this to work with pos
1338:            public String getNextTopLevelClassName(int startPos, int endPos)
1339:                    throws ClassNameNotFoundException {
1340:
1341:                acquireReadLock();
1342:                synchronized (_reduced) {
1343:                    int oldLocation = _currentLocation;
1344:
1345:                    try {
1346:                        setCurrentLocation(startPos);
1347:                        final int textLength = endPos - startPos;
1348:                        final String text = getText(startPos, textLength);
1349:
1350:                        int index;
1351:
1352:                        int indexOfClass = _findKeywordAtToplevel("class",
1353:                                text, startPos);
1354:                        int indexOfInterface = _findKeywordAtToplevel(
1355:                                "interface", text, startPos);
1356:                        int indexOfEnum = _findKeywordAtToplevel("enum", text,
1357:                                startPos);
1358:
1359:                        //If class exists at top level AND either there is no interface at top level or the index of class precedes the index of the top
1360:                        //level interface, AND the same for top level enum, then the class is the first top level declaration
1361:                        if (indexOfClass > -1
1362:                                && (indexOfInterface <= -1 || indexOfClass < indexOfInterface)
1363:                                && (indexOfEnum <= -1 || indexOfClass < indexOfEnum)) {
1364:                            index = indexOfClass + "class".length();
1365:                        } else if (indexOfInterface > -1
1366:                                && (indexOfClass <= -1 || indexOfInterface < indexOfClass)
1367:                                && (indexOfEnum <= -1 || indexOfInterface < indexOfEnum)) {
1368:                            index = indexOfInterface + "interface".length();
1369:                        } else if (indexOfEnum > -1
1370:                                && (indexOfClass <= -1 || indexOfEnum < indexOfClass)
1371:                                && (indexOfInterface <= -1 || indexOfEnum < indexOfInterface)) {
1372:                            index = indexOfEnum + "enum".length();
1373:                        } else {
1374:                            // no index was valid
1375:                            throw ClassNameNotFoundException.DEFAULT;
1376:                        }
1377:
1378:                        // we have a valid index
1379:                        return getNextIdentifier(startPos + index);
1380:                    } catch (BadLocationException ble) {
1381:                        throw new UnexpectedException(ble);
1382:                    } catch (IllegalStateException e) {
1383:                        throw new ClassNameNotFoundException(
1384:                                "No top level class name found");
1385:                    } finally {
1386:                        setCurrentLocation(oldLocation);
1387:                        releaseReadLock();
1388:                    }
1389:                }
1390:            }
1391:
1392:            /** Finds the next identifier (following a non-whitespace character) in the document starting at start. Assumes that
1393:             * read lock and _reduced lock are already held. */
1394:            private String getNextIdentifier(final int startPos)
1395:                    throws ClassNameNotFoundException {
1396:
1397:                //    _log.log("getNextIdentifer(" + startPos + ") called");
1398:
1399:                //    int index = 0;
1400:                //    int length = 0;
1401:                //    int endIndex = 0;
1402:                //    String text = "";
1403:                //    int i;
1404:                try {
1405:                    // first find index of first non whitespace (from the index in document)
1406:                    int index = getFirstNonWSCharPos(startPos);
1407:                    if (index == -1)
1408:                        throw new IllegalStateException("No identifier found");
1409:
1410:                    String text = getText();
1411:                    int length = text.length();
1412:                    int endIndex = length; //just in case no whitespace at end of file
1413:
1414:                    //      _log.log("In getNextIdentifer text = \n" + text);
1415:                    //      _log.log("index = " + index + "; length = " + length);
1416:
1417:                    //find index of next delimiter or whitespace
1418:                    char c;
1419:                    for (int i = index; i < length; i++) {
1420:                        c = text.charAt(i);
1421:                        if (!Character.isJavaIdentifierPart(c)) {
1422:                            endIndex = i;
1423:                            break;
1424:                        }
1425:                    }
1426:                    //      _log.log("endIndex = " + endIndex);
1427:                    return text.substring(index, endIndex);
1428:                } catch (BadLocationException e) {
1429:                    //      System.err.println("text =\n" + text);
1430:                    //      System.err.println("The document =\n" + getText());
1431:                    //      System.err.println("startPos = " + startPos + "; length = " + length + "; index = " + index + "; endIndex = " + endIndex);
1432:                    throw new UnexpectedException(e);
1433:                }
1434:            }
1435:
1436:            /** Finds the first occurrence of the keyword within the text (located at textOffset in this documennt) that is not 
1437:             * enclosed within a brace or comment and is followed by whitespace.
1438:             * @param keyword the keyword for which to search
1439:             * @param text in which to search
1440:             * @param textOffset Offset at which the text occurs in the document
1441:             * @return index of the keyword in text, or -1 if the keyword is not found or not followed by whitespace
1442:             */
1443:            private int _findKeywordAtToplevel(String keyword, String text,
1444:                    int textOffset) {
1445:
1446:                acquireReadLock();
1447:                synchronized (_reduced) {
1448:                    int oldLocation = _currentLocation;
1449:                    int index = 0;
1450:                    try {
1451:                        while (true) {
1452:                            index = text.indexOf(keyword, index);
1453:                            if (index == -1)
1454:                                break; // not found
1455:                            else {
1456:                                // found a match, check quality
1457:                                setCurrentLocation(textOffset + index);
1458:
1459:                                // check that the keyword is not in a comment and is followed by whitespace
1460:                                ReducedToken rt = _reduced.currentToken();
1461:                                int indexPastKeyword = index + keyword.length();
1462:                                if (indexPastKeyword < text.length()) {
1463:                                    if (rt.getState() == ReducedModelStates.FREE
1464:                                            && Character.isWhitespace(text
1465:                                                    .charAt(indexPastKeyword))) {
1466:                                        // found a match but may not be at top level
1467:                                        if (!posNotInBlock(index))
1468:                                            index = -1; //in a paren phrase, gone too far
1469:                                        break;
1470:                                    } else
1471:                                        index++; //move past so we can search again
1472:                                } else { // No space found past the keyword
1473:                                    index = -1;
1474:                                    break;
1475:                                }
1476:                            }
1477:                        }
1478:                        setCurrentLocation(oldLocation);
1479:                        //        _log.log("findKeyWord(" + keyword + ", ..., " + textOffset + ")");
1480:                        return index;
1481:                    } finally {
1482:                        releaseReadLock();
1483:                    }
1484:                }
1485:            }
1486:
1487:            /** Wrapper for Position objects to allow relinking to a new Document. */
1488:            //TODO: move this class to OpenDefinitionsDocument interface
1489:            public static class WrappedPosition implements  Position {
1490:                private Position _wrapped;
1491:
1492:                public WrappedPosition(Position w) {
1493:                    setWrapped(w);
1494:                }
1495:
1496:                public void setWrapped(Position w) {
1497:                    _wrapped = w;
1498:                }
1499:
1500:                public int getOffset() {
1501:                    return _wrapped.getOffset();
1502:                }
1503:            }
1504:
1505:            /** Factory method for created WrappedPositions. Stores the created Position instance
1506:             *  so it can be linked to a different DefinitionsDocument later. */
1507:            public Position createPosition(int offs)
1508:                    throws BadLocationException {
1509:                WrappedPosition wp = new WrappedPosition(
1510:                        createUnwrappedPosition(offs));
1511:                synchronized (_wrappedPosListLock) {
1512:                    if (_wrappedPosList == null)
1513:                        _wrappedPosList = new LinkedList<WeakReference<WrappedPosition>>();
1514:                    _wrappedPosList.add(new WeakReference<WrappedPosition>(wp));
1515:                }
1516:                return wp;
1517:            }
1518:
1519:            /** Remove all positions that have been garbage-collected from the list of positions, then return a weakly-linked
1520:             * hashmap with positions and their current offsets.
1521:             * @return list of weak references to all positions that have been created and that have not been garbage-collected yet.
1522:             */
1523:            public WeakHashMap<WrappedPosition, Integer> getWrappedPositionOffsets() {
1524:                LinkedList<WeakReference<WrappedPosition>> newList = new LinkedList<WeakReference<WrappedPosition>>();
1525:                synchronized (_wrappedPosListLock) {
1526:                    if (_wrappedPosList == null) {
1527:                        _wrappedPosList = new LinkedList<WeakReference<WrappedPosition>>();
1528:                    }
1529:                    WeakHashMap<WrappedPosition, Integer> ret = new WeakHashMap<WrappedPosition, Integer>(
1530:                            _wrappedPosList.size());
1531:
1532:                    for (WeakReference<WrappedPosition> wr : _wrappedPosList) {
1533:                        if (wr.get() != null) {
1534:                            // hasn't been garbage-collected yet
1535:                            newList.add(wr);
1536:                            ret.put(wr.get(), wr.get().getOffset());
1537:                        }
1538:                    }
1539:                    _wrappedPosList.clear();
1540:                    _wrappedPosList = newList;
1541:                    return ret;
1542:                }
1543:            }
1544:
1545:            /** Re-create the wrapped positions in the hashmap, update the wrapped position, and add them to the list.
1546:             * @param whm weakly-linked hashmap of wrapped positions and their offsets
1547:             */
1548:            public void setWrappedPositionOffsets(
1549:                    WeakHashMap<WrappedPosition, Integer> whm)
1550:                    throws BadLocationException {
1551:                synchronized (_wrappedPosListLock) {
1552:                    if (_wrappedPosList == null) {
1553:                        _wrappedPosList = new LinkedList<WeakReference<WrappedPosition>>();
1554:                    }
1555:                    _wrappedPosList.clear();
1556:
1557:                    for (Map.Entry<WrappedPosition, Integer> entry : whm
1558:                            .entrySet()) {
1559:                        if (entry.getKey() != null) {
1560:                            // hasn't been garbage-collected yet
1561:                            WrappedPosition wp = entry.getKey();
1562:                            wp.setWrapped(createUnwrappedPosition(entry
1563:                                    .getValue()));
1564:                            _wrappedPosList
1565:                                    .add(new WeakReference<WrappedPosition>(wp));
1566:                        }
1567:                    }
1568:                }
1569:            }
1570:
1571:            /** Appending any information for the reduced model from each undo command */
1572:            private static class CommandUndoableEdit extends
1573:                    AbstractUndoableEdit {
1574:                private final Runnable _undoCommand;
1575:                private final Runnable _redoCommand;
1576:
1577:                public CommandUndoableEdit(final Runnable undoCommand,
1578:                        final Runnable redoCommand) {
1579:                    _undoCommand = undoCommand;
1580:                    _redoCommand = redoCommand;
1581:                }
1582:
1583:                public void undo() throws CannotUndoException {
1584:                    super .undo();
1585:                    _undoCommand.run();
1586:                }
1587:
1588:                public void redo() throws CannotRedoException {
1589:                    super .redo();
1590:                    _redoCommand.run();
1591:                }
1592:
1593:                public boolean isSignificant() {
1594:                    return false;
1595:                }
1596:            }
1597:
1598:            /**
1599:             * Getter method for CompoundUndoManager
1600:             * @return _undoManager
1601:             */
1602:            public CompoundUndoManager getUndoManager() {
1603:                return _undoManager;
1604:            }
1605:
1606:            /** Resets the undo manager. */
1607:            public void resetUndoManager() {
1608:                _undoManager = new CompoundUndoManager(_notifier);
1609:                _undoManager.setLimit(UNDO_LIMIT);
1610:            }
1611:
1612:            /** Public accessor for the next undo action. */
1613:            public UndoableEdit getNextUndo() {
1614:                return _undoManager.getNextUndo();
1615:            }
1616:
1617:            /** Public accessor for the next undo action. */
1618:            public UndoableEdit getNextRedo() {
1619:                return _undoManager.getNextRedo();
1620:            }
1621:
1622:            /** Informs this document's undo manager that the document has been saved. */
1623:            public void documentSaved() {
1624:                _undoManager.documentSaved();
1625:            }
1626:
1627:            protected int startCompoundEdit() {
1628:                return _undoManager.startCompoundEdit();
1629:            }
1630:
1631:            protected void endCompoundEdit(int key) {
1632:                _undoManager.endCompoundEdit(key);
1633:            }
1634:
1635:            //This method added for FrenchKeyBoardFix
1636:            protected void endLastCompoundEdit() {
1637:                _undoManager.endLastCompoundEdit();
1638:            }
1639:
1640:            protected void addUndoRedo(
1641:                    AbstractDocument.DefaultDocumentEvent chng,
1642:                    Runnable undoCommand, Runnable doCommand) {
1643:                chng.addEdit(new CommandUndoableEdit(undoCommand, doCommand));
1644:            }
1645:
1646:            /**
1647:             * Is used to be able to call editToBeUndone and editToBeRedone since they
1648:             * are protected methods in UndoManager
1649:             */
1650:            /*
1651:            private class OurUndoManager extends UndoManager {
1652:              private boolean _compoundEditState = false;
1653:              private OurCompoundEdit _compoundEdit;
1654:
1655:              public void startCompoundEdit() {
1656:                if (_compoundEditState) {
1657:                  throw new IllegalStateException("Cannot start a compound edit while making a compound edit");
1658:                }
1659:                _compoundEditState = true;
1660:                _compoundEdit = new OurCompoundEdit();
1661:              }
1662:
1663:              public void endCompoundEdit() {
1664:                if (!_compoundEditState) {
1665:                  throw new IllegalStateException("Cannot end a compound edit while not making a compound edit");
1666:                }
1667:                _compoundEditState = false;
1668:                _compoundEdit.end();
1669:                super.addEdit(_compoundEdit);
1670:              }
1671:
1672:              public UndoableEdit getNextUndo() {
1673:                return editToBeUndone();
1674:              }
1675:
1676:              public UndoableEdit getNextRedo() {
1677:                return editToBeRedone();
1678:              }
1679:
1680:              public boolean addEdit(UndoableEdit e) {
1681:                if (_compoundEditState) {
1682:                  return _compoundEdit.addEdit(e);
1683:                }
1684:                else {
1685:                  return super.addEdit(e);
1686:                }
1687:              }
1688:            }
1689:
1690:
1691:            public java.util.Vector getEdits() {
1692:               return _undoManager._compoundEdit.getEdits();
1693:            }
1694:
1695:            private class OurCompoundEdit extends CompoundEdit {
1696:               public java.util.Vector getEdits() {
1697:                  return edits;
1698:               }
1699:            }
1700:             */
1701:
1702:            /**
1703:             * used to help track down memory leaks
1704:             */
1705:            //  protected void finalize() throws Throwable{
1706:            //    System.out.println("destroying DefDocument for " + _odd);
1707:            //    super.finalize();
1708:            //  }
1709:            //  
1710:            //  private List<Pair<Option, OptionListener>> _optionListeners = new LinkedList<Option, OptionListener>>();
1711:            //
1712:            //  public void clearOptionListeners() {
1713:            //    for (Pair<Option, OptionListener> l: _optionListeners) {
1714:            //      DrJava.getConfig().removeOptionListener( l.getFirst(), l.getSecond());
1715:            //    }
1716:            //    _optionListeners.clear();
1717:            //  }
1718:            //  
1719:            //  public void addOptionListener(Option op, OptionListener l) {
1720:            //    DrJava.getConfig().addOptionListener(op, l);
1721:            //    _optionListeners.add(new Pair<Option, OptionListener>(op, l));
1722:            //  }
1723:            /** This list of listeners to notify when we are finalized. */
1724:            private List<FinalizationListener<DefinitionsDocument>> _finalizationListeners = new LinkedList<FinalizationListener<DefinitionsDocument>>();
1725:
1726:            /**
1727:             * Registers a finalization listener with the specific instance of the ddoc
1728:             * <p><b>NOTE:</b><i>This should only be used by test cases.  This is to ensure that
1729:             * we don't spring memory leaks by allowing our unit tests to keep track of 
1730:             * whether objects are being finalized (garbage collected)</i></p>
1731:             * @param fl the listener to register
1732:             */
1733:            public void addFinalizationListener(
1734:                    FinalizationListener<DefinitionsDocument> fl) {
1735:                synchronized (_finalizationListeners) {
1736:                    _finalizationListeners.add(fl);
1737:                }
1738:            }
1739:
1740:            public List<FinalizationListener<DefinitionsDocument>> getFinalizationListeners() {
1741:                return _finalizationListeners;
1742:            }
1743:
1744:            /** This is called when this method is GC'd.  Since this class implements
1745:             *  edu.rice.cs.drjava.model.Finalizable, it must notify its listeners
1746:             */
1747:            protected void finalize() {
1748:                FinalizationEvent<DefinitionsDocument> fe = new FinalizationEvent<DefinitionsDocument>(
1749:                        this );
1750:                synchronized (_finalizationListeners) {
1751:                    for (FinalizationListener<DefinitionsDocument> fl : _finalizationListeners) {
1752:                        fl.finalized(fe);
1753:                    }
1754:                }
1755:            }
1756:
1757:            public String toString() {
1758:                return "ddoc for " + _odd;
1759:            }
1760:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.