Source Code Cross Referenced for DocumentLine.java in  » IDE-Netbeans » openide » org » openide » text » 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 Netbeans » openide » org.openide.text 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003:         *
0004:         * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005:         *
0006:         * The contents of this file are subject to the terms of either the GNU
0007:         * General Public License Version 2 only ("GPL") or the Common
0008:         * Development and Distribution License("CDDL") (collectively, the
0009:         * "License"). You may not use this file except in compliance with the
0010:         * License. You can obtain a copy of the License at
0011:         * http://www.netbeans.org/cddl-gplv2.html
0012:         * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013:         * specific language governing permissions and limitations under the
0014:         * License.  When distributing the software, include this License Header
0015:         * Notice in each file and include the License file at
0016:         * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
0017:         * particular file as subject to the "Classpath" exception as provided
0018:         * by Sun in the GPL Version 2 section of the License file that
0019:         * accompanied this code. If applicable, add the following below the
0020:         * License Header, with the fields enclosed by brackets [] replaced by
0021:         * your own identifying information:
0022:         * "Portions Copyrighted [year] [name of copyright owner]"
0023:         *
0024:         * Contributor(s):
0025:         *
0026:         * The Original Software is NetBeans. The Initial Developer of the Original
0027:         * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
0028:         * Microsystems, Inc. All Rights Reserved.
0029:         *
0030:         * If you wish your version of this file to be governed by only the CDDL
0031:         * or only the GPL Version 2, indicate your decision by adding
0032:         * "[Contributor] elects to include this software in this distribution
0033:         * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034:         * single choice of license, a recipient has the option to distribute
0035:         * your version of this file under either the CDDL, the GPL Version 2 or
0036:         * to extend the choice of license to its licensees as provided above.
0037:         * However, if you add GPL Version 2 code and therefore, elected the GPL
0038:         * Version 2 license, then the option applies only if the new code is
0039:         * made subject to such option by the copyright holder.
0040:         */
0041:        package org.openide.text;
0042:
0043:        import java.util.logging.Level;
0044:        import java.util.logging.Logger;
0045:        import org.openide.text.EnhancedChangeEvent;
0046:
0047:        import java.io.*;
0048:
0049:        import java.util.*;
0050:
0051:        import javax.swing.event.*;
0052:        import javax.swing.text.*;
0053:
0054:        /** Implementation of a line in a {@link StyledDocument}.
0055:         * One object
0056:         * of this class represents a line in the document by holding
0057:         * a {@link PositionRef}, which can represent a position in an open or
0058:         * closed document.
0059:         *
0060:         * @author Jaroslav Tulach, David Konecny
0061:         */
0062:        public abstract class DocumentLine extends Line {
0063:            /** weak map that assignes to editor supports whether they have current or error line
0064:             * selected. (EditorSupport, DocumentLine[2]), where Line[0] is current and Line[1] is error */
0065:            private static Map<CloneableEditorSupport, DocumentLine[]> assigned = new WeakHashMap<CloneableEditorSupport, DocumentLine[]>(
0066:                    5);
0067:            static final long serialVersionUID = 3213776466939427487L;
0068:
0069:            /** reference to one position on the line */
0070:            protected PositionRef pos;
0071:
0072:            /** is breakpoint there - presistent state
0073:             @deprecated since 1.20 */
0074:            @Deprecated
0075:            private boolean breakpoint;
0076:
0077:            /** error line  - transient state
0078:             @deprecated since 1.20 */
0079:            @Deprecated
0080:            private transient boolean error;
0081:
0082:            /** current line - transient state
0083:             @deprecated since 1.20 */
0084:            @Deprecated
0085:            private transient boolean current;
0086:
0087:            /** listener for changes of state of the document */
0088:            private transient LR listener;
0089:
0090:            /** weak document listener assigned to the document or null */
0091:            private transient DocumentListener docL;
0092:
0093:            /** List of Line.Part which exist for this line*/
0094:            private List<Part> lineParts = new ArrayList<Part>(3);
0095:
0096:            /** Constructor.
0097:             * @param obj context we belong to
0098:             * @param pos position on the line
0099:             *
0100:             * @since 4.3
0101:             */
0102:            public DocumentLine(org.openide.util.Lookup obj, PositionRef pos) {
0103:                super (obj);
0104:                this .pos = pos;
0105:            }
0106:
0107:            /** Init listeners
0108:             */
0109:            void init() {
0110:                listener = new LR();
0111:                pos.getCloneableEditorSupport().addChangeListener(
0112:                        org.openide.util.WeakListeners.change(listener, pos
0113:                                .getCloneableEditorSupport()));
0114:            }
0115:
0116:            /* Get the line number.
0117:             * The number may change if the
0118:             * text is modified.
0119:             *
0120:             * @return Returns current line number.
0121:             */
0122:            public int getLineNumber() {
0123:                try {
0124:                    return pos.getLine();
0125:                } catch (IOException ex) {
0126:                    // what else?
0127:                    return 0;
0128:                }
0129:            }
0130:
0131:            /* Shows the line.
0132:             * @param kind one of SHOW_XXX constants.
0133:             * @column the column of this line which should be selected
0134:             */
0135:            public abstract void show(int kind, int column);
0136:
0137:            /* Sets the breakpoint. */
0138:            @SuppressWarnings("deprecation")
0139:            public void setBreakpoint(boolean b) {
0140:                if (breakpoint != b) {
0141:                    breakpoint = b;
0142:                    refreshState();
0143:                }
0144:            }
0145:
0146:            /* Tests if the breakpoint is set. */
0147:            @SuppressWarnings("deprecation")
0148:            public boolean isBreakpoint() {
0149:                return breakpoint;
0150:            }
0151:
0152:            /* Marks the error. */
0153:            @SuppressWarnings("deprecation")
0154:            public void markError() {
0155:                DocumentLine previous = registerLine(1, this );
0156:
0157:                if (previous != null) {
0158:                    previous.error = false;
0159:                    previous.refreshState();
0160:                }
0161:
0162:                error = true;
0163:
0164:                refreshState();
0165:            }
0166:
0167:            /* Unmarks error at this line. */
0168:            @SuppressWarnings("deprecation")
0169:            public void unmarkError() {
0170:                error = false;
0171:                registerLine(1, null);
0172:
0173:                refreshState();
0174:            }
0175:
0176:            /* Marks this line as current. */
0177:            @SuppressWarnings("deprecation")
0178:            public void markCurrentLine() {
0179:                DocumentLine previous = registerLine(0, this );
0180:
0181:                if (previous != null) {
0182:                    previous.current = false;
0183:                    previous.refreshState();
0184:                }
0185:
0186:                current = true;
0187:                refreshState();
0188:            }
0189:
0190:            /* Unmarks this line as current. */
0191:            @SuppressWarnings("deprecation")
0192:            public void unmarkCurrentLine() {
0193:                current = false;
0194:                registerLine(0, null);
0195:
0196:                refreshState();
0197:            }
0198:
0199:            /** Refreshes the current line.
0200:             *
0201:             * @deprecated since 1.20. */
0202:            @Deprecated
0203:            synchronized void refreshState() {
0204:                StyledDocument doc = pos.getCloneableEditorSupport()
0205:                        .getDocument();
0206:
0207:                if (doc != null) {
0208:                    // the document is in memory, mark the state
0209:                    if (docL != null) {
0210:                        doc.removeDocumentListener(docL);
0211:                    }
0212:
0213:                    // error line
0214:                    if (error) {
0215:                        NbDocument.markError(doc, pos.getOffset());
0216:
0217:                        doc
0218:                                .addDocumentListener(docL = org.openide.util.WeakListeners
0219:                                        .document(listener, doc));
0220:
0221:                        return;
0222:                    }
0223:
0224:                    // current line
0225:                    if (current) {
0226:                        NbDocument.markCurrent(doc, pos.getOffset());
0227:
0228:                        return;
0229:                    }
0230:
0231:                    // breakpoint line
0232:                    if (breakpoint) {
0233:                        NbDocument.markBreakpoint(doc, pos.getOffset());
0234:
0235:                        return;
0236:                    }
0237:
0238:                    NbDocument.markNormal(doc, pos.getOffset());
0239:
0240:                    return;
0241:                }
0242:            }
0243:
0244:            public int hashCode() {
0245:                return pos.getCloneableEditorSupport().hashCode();
0246:            }
0247:
0248:            public boolean equals(Object o) {
0249:                if (o instanceof  DocumentLine) {
0250:                    DocumentLine dl = (DocumentLine) o;
0251:
0252:                    if (dl.pos.getCloneableEditorSupport() == pos
0253:                            .getCloneableEditorSupport()) {
0254:                        return dl.getLineNumber() == getLineNumber();
0255:                    }
0256:                }
0257:
0258:                return false;
0259:            }
0260:
0261:            //
0262:            // Work with global hash table
0263:            //
0264:
0265:            /** Register this line as the one stored
0266:             * under indx-index (0 = current, 1 = error).
0267:             *
0268:             * @param indx index to register
0269:             * @param line value to add (this or null)
0270:             * @return the previous value
0271:             *
0272:             * @deprecated since 1.20 */
0273:            @Deprecated
0274:            private DocumentLine registerLine(int indx, DocumentLine line) {
0275:                DocumentLine prev;
0276:
0277:                CloneableEditorSupport es = pos.getCloneableEditorSupport();
0278:
0279:                DocumentLine[] arr = assigned.get(es);
0280:
0281:                if (arr != null) {
0282:                    // remember the previous
0283:                    prev = arr[indx];
0284:                } else {
0285:                    // create new array
0286:                    arr = new DocumentLine[2];
0287:                    assigned.put(es, arr);
0288:                    prev = null;
0289:                }
0290:
0291:                arr[indx] = line;
0292:
0293:                return prev;
0294:            }
0295:
0296:            //
0297:            // Serialization
0298:            //
0299:
0300:            /** Write fields.
0301:             */
0302:            private void writeObject(ObjectOutputStream oos) throws IOException {
0303:                // do not do default read/write object
0304:                oos.writeObject(pos);
0305:                oos.writeBoolean(breakpoint);
0306:            }
0307:
0308:            /** Read important fields.
0309:             */
0310:            private void readObject(ObjectInputStream ois) throws IOException,
0311:                    ClassNotFoundException {
0312:                pos = (PositionRef) ois.readObject();
0313:                setBreakpoint(ois.readBoolean());
0314:                lineParts = new ArrayList<Part>(3);
0315:            }
0316:
0317:            /** Register line.
0318:             */
0319:            Object readResolve() throws ObjectStreamException {
0320:                //        return Set.registerLine (this);
0321:                //Set.registerPendingLine(this);
0322:                return this .pos.getCloneableEditorSupport().getLineSet()
0323:                        .registerLine(this );
0324:            }
0325:
0326:            /** Add annotation to this Annotatable class
0327:             * @param anno annotation which will be attached to this class */
0328:            protected void addAnnotation(Annotation anno) {
0329:                super .addAnnotation(anno);
0330:
0331:                StyledDocument doc = pos.getCloneableEditorSupport()
0332:                        .getDocument();
0333:
0334:                // document is not opened and so the annotation will be added to document later
0335:                if (doc == null) {
0336:                    return;
0337:                }
0338:
0339:                pos.getCloneableEditorSupport().prepareDocument()
0340:                        .waitFinished();
0341:
0342:                try {
0343:                    if (!anno.isInDocument()) {
0344:                        anno.setInDocument(true);
0345:
0346:                        // #33165 - find position that is surely at begining of line
0347:                        FindAnnotationPosition fap = new FindAnnotationPosition(
0348:                                doc, pos.getPosition());
0349:                        doc.render(fap);
0350:                        NbDocument.addAnnotation(doc, fap
0351:                                .getAnnotationPosition(), -1, anno);
0352:                    }
0353:                } catch (IOException ex) {
0354:                    Logger.getLogger(DocumentLine.class.getName()).log(
0355:                            Level.WARNING, null, ex);
0356:                }
0357:            }
0358:
0359:            /** Remove annotation to this Annotatable class
0360:             * @param anno annotation which will be detached from this class  */
0361:            protected void removeAnnotation(Annotation anno) {
0362:                super .removeAnnotation(anno);
0363:
0364:                StyledDocument doc = pos.getCloneableEditorSupport()
0365:                        .getDocument();
0366:
0367:                // document is not opened and so no annotation is attached to it
0368:                if (doc == null) {
0369:                    return;
0370:                }
0371:
0372:                pos.getCloneableEditorSupport().prepareDocument()
0373:                        .waitFinished();
0374:
0375:                if (anno.isInDocument()) {
0376:                    anno.setInDocument(false);
0377:                    NbDocument.removeAnnotation(doc, anno);
0378:                }
0379:            }
0380:
0381:            /** When document is opened or closed the annotations must be added or
0382:             * removed.
0383:             * @since 1.27 */
0384:            void attachDetachAnnotations(StyledDocument doc, boolean closing) {
0385:                // #33165 - find position that is surely at begining of line
0386:                Position annoPos = null;
0387:
0388:                if (!closing) {
0389:                    try {
0390:                        annoPos = pos.getPosition();
0391:
0392:                        FindAnnotationPosition fap = new FindAnnotationPosition(
0393:                                doc, annoPos);
0394:                        doc.render(fap);
0395:                        annoPos = fap.getAnnotationPosition();
0396:                    } catch (IOException ex) {
0397:                        Logger.getLogger(DocumentLine.class.getName()).log(
0398:                                Level.WARNING, null, ex);
0399:                    }
0400:                }
0401:
0402:                List<? extends Annotation> list = getAnnotations();
0403:                synchronized (list) {
0404:                    for (Annotation anno : list) {
0405:                        if (!closing) {
0406:                            if (!anno.isInDocument()) {
0407:                                anno.setInDocument(true);
0408:                                NbDocument
0409:                                        .addAnnotation(doc, annoPos, -1, anno);
0410:                            }
0411:                        } else {
0412:                            if (anno.isInDocument()) {
0413:                                anno.setInDocument(false);
0414:                                NbDocument.removeAnnotation(doc, anno);
0415:                            }
0416:                        }
0417:                    }
0418:                }
0419:
0420:                // notify also all Line.Part attached to this Line
0421:                for (Part p : lineParts) {
0422:                    p.attachDetachAnnotations(doc, closing);
0423:                }
0424:            }
0425:
0426:            public String getText() {
0427:                final StyledDocument doc = pos.getCloneableEditorSupport()
0428:                        .getDocument();
0429:
0430:                // document is not opened
0431:                if (doc == null) {
0432:                    return null;
0433:                }
0434:
0435:                final String[] retStringArray = new String[1];
0436:                doc.render(new Runnable() {
0437:                    public void run() {
0438:                        // Part of #33165 - the following code is wrapped by doc.render()
0439:                        int lineNumber = getLineNumber();
0440:                        int lineStart = NbDocument.findLineOffset(doc,
0441:                                lineNumber);
0442:
0443:                        // #24434: Check whether the next line exists
0444:                        // (the current one could be the last one).
0445:                        int lineEnd;
0446:
0447:                        if ((lineNumber + 1) >= NbDocument.findLineRootElement(
0448:                                doc).getElementCount()) {
0449:                            lineEnd = doc.getLength();
0450:                        } else {
0451:                            lineEnd = NbDocument.findLineOffset(doc,
0452:                                    lineNumber + 1);
0453:                        }
0454:
0455:                        try {
0456:                            retStringArray[0] = doc.getText(lineStart, lineEnd
0457:                                    - lineStart);
0458:                        } catch (BadLocationException ex) {
0459:                            Logger.getLogger(DocumentLine.class.getName()).log(
0460:                                    Level.WARNING, null, ex);
0461:                            retStringArray[0] = null;
0462:                        }
0463:
0464:                        // End of the code wrapped by doc.render()
0465:                    }
0466:                });
0467:
0468:                return retStringArray[0];
0469:            }
0470:
0471:            /** Attach created Line.Part to the parent Line */
0472:            void addLinePart(DocumentLine.Part linePart) {
0473:                lineParts.add(linePart);
0474:            }
0475:
0476:            /** Move Line.Part from this Line to a new one*/
0477:            void moveLinePart(DocumentLine.Part linePart, DocumentLine newLine) {
0478:                lineParts.remove(linePart);
0479:                newLine.addLinePart(linePart);
0480:                linePart.changeLine(newLine);
0481:            }
0482:
0483:            /** Notify Line.Part(s) that content of the line was changed and that Line.Part(s) may be affected by that*/
0484:            void notifyChange(DocumentEvent p0, DocumentLine.Set set,
0485:                    StyledDocument doc) {
0486:                DocumentLine.Part part;
0487:
0488:                for (int i = 0; i < lineParts.size();) {
0489:                    part = lineParts.get(i);
0490:
0491:                    // notify Line.Part about the change
0492:                    part.handleDocumentChange(p0);
0493:
0494:                    // if necessary move Line.Part to new Line
0495:                    if (NbDocument.findLineNumber(doc, part.getOffset()) != part
0496:                            .getLine().getLineNumber()) {
0497:                        DocumentLine line = (DocumentLine) set
0498:                                .getCurrent(NbDocument.findLineNumber(doc, part
0499:                                        .getOffset()));
0500:                        moveLinePart(part, line);
0501:                    } else {
0502:                        i++;
0503:                    }
0504:                }
0505:
0506:                // #33165 - fix the position in the positionRef in case this line changes
0507:                // and reattach the annotations.
0508:                // The fix of #32764 in notifyMove() would only reattach
0509:                // the annotations in case the position does not go at a line begining
0510:                // after the modification but that is not enough
0511:                // to fix undo-related issues.
0512:                Position p;
0513:
0514:                try {
0515:                    p = pos.getPosition();
0516:                } catch (IOException ex) {
0517:                    Logger.getLogger(DocumentLine.class.getName()).log(
0518:                            Level.WARNING, null, ex);
0519:                    p = null;
0520:                }
0521:
0522:                if (p != null) {
0523:                    int lineStartOffset = NbDocument.findLineOffset(doc,
0524:                            NbDocument.findLineNumber(doc, p.getOffset()));
0525:                    CloneableEditorSupport support = pos
0526:                            .getCloneableEditorSupport();
0527:
0528:                    // Recreate positionRef unconditionally to avoid undo problems
0529:                    pos = new PositionRef(support.getPositionManager(),
0530:                            lineStartOffset, Position.Bias.Forward);
0531:
0532:                    List<? extends Annotation> annos = getAnnotations();
0533:                    synchronized (annos) {
0534:                        if (annos.size() > 0) {
0535:                            try {
0536:                                p = pos.getPosition();
0537:                            } catch (IOException e) {
0538:                                throw new IllegalArgumentException(); // should not fail
0539:                            }
0540:
0541:                            for (Annotation anno : annos) {
0542:
0543:                                if (anno.isInDocument()) {
0544:                                    anno.setInDocument(false);
0545:                                    NbDocument.removeAnnotation(support
0546:                                            .getDocument(), anno);
0547:                                }
0548:
0549:                                if (!anno.isInDocument()) {
0550:                                    anno.setInDocument(true);
0551:                                    NbDocument.addAnnotation(support
0552:                                            .getDocument(), p, -1, anno);
0553:                                }
0554:                            }
0555:                        }
0556:                    }
0557:                }
0558:            }
0559:
0560:            /** Notify Line.Part(s) that line was moved. */
0561:            void notifyMove() {
0562:                updatePositionRef();
0563:
0564:                for (int i = 0; i < lineParts.size(); i++) {
0565:                    ((DocumentLine.Part) lineParts.get(i)).firePropertyChange(
0566:                            Line.Part.PROP_LINE, null, null);
0567:                }
0568:            }
0569:
0570:            /** Updates <code>pos</code> the way it points at the start of line. */
0571:            private void updatePositionRef() {
0572:                // #33165 - Moved handling that follows into notifyChange()
0573:                //  due to problems with undo operations.
0574:                // Rest of notifyMove() should work as the code in notifyChange()
0575:                // in fact includes the same work as done here and notifyChange()
0576:                // is called before notifyMove()
0577:                // (see linesChanged()/linesMoved() in LineListener).
0578:
0579:                /*        CloneableEditorSupport support = pos.getCloneableEditorSupport();
0580:                        int startOffset = NbDocument.findLineOffset(support.getDocument(),
0581:                            getLineNumber());
0582:
0583:                        if(pos.getOffset() != startOffset) {
0584:                            pos = new PositionRef(
0585:                                support.getPositionManager(), startOffset, Position.Bias.Forward
0586:                            );
0587:
0588:                            // fix of #32764
0589:                            List annos = getAnnotations();
0590:                            for (int i=0; i<annos.size(); i++) {
0591:                                Annotation anno = (Annotation)annos.get(i);
0592:                                if (anno.isInDocument()) {
0593:                                    anno.setInDocument(false);
0594:                                    NbDocument.removeAnnotation(support.getDocument(), anno);
0595:                                }
0596:
0597:                                try {
0598:                                    if (!anno.isInDocument()) {
0599:                                        anno.setInDocument(true);
0600:                                        NbDocument.addAnnotation (support.getDocument(), pos.getPosition(), -1, anno);
0601:                                    }
0602:                                }  catch (IOException ex) {
0603:                                    ErrorManager.getDefault ().notify ( ErrorManager.EXCEPTION, ex);
0604:                                }
0605:                            }
0606:                        }
0607:                 */
0608:            }
0609:
0610:            /**
0611:             * Runnable used to find a position where the annotation should be attached.
0612:             * It is intended to be run under document's readlock.
0613:             */
0614:            private static final class FindAnnotationPosition implements 
0615:                    Runnable {
0616:                private StyledDocument doc;
0617:                private Position annoPos;
0618:
0619:                FindAnnotationPosition(StyledDocument doc, Position pos) {
0620:                    this .doc = doc;
0621:                    this .annoPos = pos; // by default assume the given one is correct
0622:                }
0623:
0624:                public void run() {
0625:                    int offset = annoPos.getOffset();
0626:                    int lineStartOffset = doc.getParagraphElement(offset)
0627:                            .getStartOffset();
0628:
0629:                    if (offset != lineStartOffset) { // not at line start -> correct
0630:
0631:                        try {
0632:                            annoPos = doc.createPosition(lineStartOffset);
0633:                        } catch (BadLocationException e) {
0634:                            throw new IllegalArgumentException(); // should never fail
0635:                        }
0636:                    }
0637:                }
0638:
0639:                Position getAnnotationPosition() {
0640:                    return annoPos;
0641:                }
0642:            }
0643:
0644:            /** Implementation of Line.Part abstract class*/
0645:            static class Part extends Line.Part {
0646:                /** Reference of this part to the document*/
0647:                private PositionRef position;
0648:
0649:                /** Reference to Line to which this part belongs*/
0650:                private Line line;
0651:
0652:                /** Length of the annotated text*/
0653:                private int length;
0654:
0655:                /** Offset of this Part before the modification. This member is used in
0656:                 * listener on document changes and it is updated after each change. */
0657:                private int previousOffset;
0658:
0659:                public Part(Line line, PositionRef position, int length) {
0660:                    this .position = position;
0661:                    this .line = line;
0662:                    previousOffset = position.getOffset();
0663:                    this .length = limitLength(length);
0664:                }
0665:
0666:                private int limitLength(int suggestedLength) {
0667:                    Document d = position.getCloneableEditorSupport()
0668:                            .getDocument();
0669:                    if (d == null) {
0670:                        // Can happen when closing a document, don't know why.
0671:                        return suggestedLength;
0672:                    }
0673:                    int end = position.getOffset() + suggestedLength;
0674:
0675:                    if (end > d.getLength()) {
0676:                        end = d.getLength();
0677:                    }
0678:
0679:                    if (end < position.getOffset()) {
0680:                        return 0;
0681:                    }
0682:
0683:                    try {
0684:                        String text = d.getText(position.getOffset(), end
0685:                                - position.getOffset());
0686:                        int newLine = text.indexOf('\n');
0687:
0688:                        return (newLine == -1) ? text.length() : (newLine + 1);
0689:                    } catch (BadLocationException ex) {
0690:                        IllegalStateException i = new IllegalStateException(ex
0691:                                .getMessage());
0692:                        i.initCause(ex);
0693:                        throw i;
0694:                    }
0695:                }
0696:
0697:                /** Start column of annotation */
0698:                public int getColumn() {
0699:                    try {
0700:                        return position.getColumn();
0701:                    } catch (IOException ex) {
0702:                        return 0; //TODO: change this
0703:                    }
0704:                }
0705:
0706:                /** Length of the annotated text. The length does not cross line end. If the annotated text is
0707:                 * split during the editing, the annotation is shorten till the end of the line. Modules can listen on
0708:                 * changes of this value*/
0709:                public int getLength() {
0710:                    return length;
0711:                }
0712:
0713:                /** Line can change during editting*/
0714:                public Line getLine() {
0715:                    return line;
0716:                }
0717:
0718:                /** Offset of the Line.Part*/
0719:                int getOffset() {
0720:                    return position.getOffset();
0721:                }
0722:
0723:                /** Line can change during editting*/
0724:                void changeLine(Line line) {
0725:                    this .line = line;
0726:
0727:                    // TODO: check whether there is really some change
0728:                    firePropertyChange(PROP_LINE_NUMBER, null, line);
0729:                }
0730:
0731:                /** Add annotation to this Annotatable class
0732:                 * @param anno annotation which will be attached to this class */
0733:                protected void addAnnotation(Annotation anno) {
0734:                    super .addAnnotation(anno);
0735:
0736:                    StyledDocument doc = position.getCloneableEditorSupport()
0737:                            .getDocument();
0738:
0739:                    // document is not opened and so the annotation will be added to document later
0740:                    if (doc == null) {
0741:                        return;
0742:                    }
0743:
0744:                    position.getCloneableEditorSupport().prepareDocument()
0745:                            .waitFinished();
0746:
0747:                    try {
0748:                        if (!anno.isInDocument()) {
0749:                            anno.setInDocument(true);
0750:                            NbDocument.addAnnotation(doc, position
0751:                                    .getPosition(), length, anno);
0752:                        }
0753:                    } catch (IOException ex) {
0754:                        Logger.getLogger(DocumentLine.class.getName()).log(
0755:                                Level.WARNING, null, ex);
0756:                    }
0757:                }
0758:
0759:                /** Remove annotation to this Annotatable class
0760:                 * @param anno annotation which will be detached from this class  */
0761:                protected void removeAnnotation(Annotation anno) {
0762:                    super .removeAnnotation(anno);
0763:
0764:                    StyledDocument doc = position.getCloneableEditorSupport()
0765:                            .getDocument();
0766:
0767:                    // document is not opened and so no annotation is attached to it
0768:                    if (doc == null) {
0769:                        return;
0770:                    }
0771:
0772:                    position.getCloneableEditorSupport().prepareDocument()
0773:                            .waitFinished();
0774:
0775:                    if (anno.isInDocument()) {
0776:                        anno.setInDocument(false);
0777:                        NbDocument.removeAnnotation(doc, anno);
0778:                    }
0779:                }
0780:
0781:                public String getText() {
0782:                    final StyledDocument doc = position
0783:                            .getCloneableEditorSupport().getDocument();
0784:
0785:                    // document is not opened
0786:                    if (doc == null) {
0787:                        return null;
0788:                    }
0789:
0790:                    final String[] retStringArray = new String[1];
0791:                    doc.render(new Runnable() {
0792:                        public void run() {
0793:                            // Part of #33165 - the following code is wrapped by doc.render()
0794:                            try {
0795:                                int p = position.getOffset();
0796:
0797:                                if (p >= doc.getLength()) {
0798:                                    retStringArray[0] = "";
0799:                                } else {
0800:                                    retStringArray[0] = doc.getText(position
0801:                                            .getOffset(), getLength());
0802:                                }
0803:                            } catch (BadLocationException ex) {
0804:                                Logger.getLogger(DocumentLine.class.getName())
0805:                                        .log(Level.WARNING, null, ex);
0806:                                retStringArray[0] = null;
0807:                            }
0808:
0809:                            // End of the code wrapped by doc.render()
0810:                        }
0811:                    });
0812:
0813:                    return retStringArray[0];
0814:                }
0815:
0816:                /** When document is opened or closed the annotations must be added or
0817:                 * removed.*/
0818:                void attachDetachAnnotations(StyledDocument doc, boolean closing) {
0819:                    List<? extends Annotation> list = getAnnotations();
0820:
0821:                    synchronized (list) {
0822:                        for (Annotation anno : list) {
0823:
0824:                            if (!closing) {
0825:                                try {
0826:                                    if (!anno.isInDocument()) {
0827:                                        anno.setInDocument(true);
0828:                                        NbDocument.addAnnotation(doc, position
0829:                                                .getPosition(), getLength(),
0830:                                                anno);
0831:                                    }
0832:                                } catch (IOException ex) {
0833:                                    Logger.getLogger(
0834:                                            DocumentLine.class.getName()).log(
0835:                                            Level.WARNING, null, ex);
0836:                                }
0837:                            } else {
0838:                                if (anno.isInDocument()) {
0839:                                    anno.setInDocument(false);
0840:                                    NbDocument.removeAnnotation(doc, anno);
0841:                                }
0842:                            }
0843:                        }
0844:                    }
0845:                }
0846:
0847:                /** Handle DocumentChange event. If the change affect this Part, fire
0848:                 * the PROP_TEXT event. */
0849:                void handleDocumentChange(DocumentEvent p0) {
0850:                    if (p0.getType().equals(DocumentEvent.EventType.INSERT)) {
0851:                        if ((p0.getOffset() >= previousOffset)
0852:                                && (p0.getOffset() < (previousOffset + getLength()))) {
0853:                            firePropertyChange(Annotatable.PROP_TEXT, null,
0854:                                    null);
0855:                        }
0856:                    }
0857:
0858:                    if (p0.getType().equals(DocumentEvent.EventType.REMOVE)) {
0859:                        if (((p0.getOffset() >= previousOffset) && (p0
0860:                                .getOffset() < (previousOffset + getLength())))
0861:                                || ((p0.getOffset() < previousOffset) && ((p0
0862:                                        .getOffset() + p0.getLength()) > previousOffset))) {
0863:                            length = limitLength(length);
0864:                            firePropertyChange(Annotatable.PROP_TEXT, null,
0865:                                    null);
0866:                        }
0867:                    }
0868:
0869:                    if ((p0.getType().equals(DocumentEvent.EventType.INSERT) || p0
0870:                            .getType().equals(DocumentEvent.EventType.REMOVE))
0871:                            && (p0.getOffset() < previousOffset)) {
0872:                        firePropertyChange(Line.Part.PROP_COLUMN, null, null);
0873:                    }
0874:
0875:                    previousOffset = position.getOffset();
0876:                }
0877:            }
0878:
0879:            /** Definition of actions performed in Listener */
0880:            private final class LR implements  Runnable, ChangeListener,
0881:                    DocumentListener {
0882:                private static final int REFRESH = 0;
0883:                private static final int UNMARK = 1;
0884:                private static final int ATTACH_DETACH = 2;
0885:                private int actionId;
0886:                private EnhancedChangeEvent ev;
0887:
0888:                public LR() {
0889:                }
0890:
0891:                public LR(int actionId) {
0892:                    this .actionId = actionId;
0893:                }
0894:
0895:                public LR(EnhancedChangeEvent ev) {
0896:                    this .actionId = ATTACH_DETACH;
0897:                    this .ev = ev;
0898:                }
0899:
0900:                public void run() {
0901:                    switch (actionId) {
0902:                    case REFRESH:
0903:                        refreshState();
0904:
0905:                        break;
0906:
0907:                    case UNMARK:
0908:                        unmarkError();
0909:
0910:                        break;
0911:
0912:                    case ATTACH_DETACH:
0913:                        attachDetachAnnotations(ev.getDocument(), ev
0914:                                .isClosingDocument());
0915:                        ev = null;
0916:
0917:                        break;
0918:                    }
0919:                }
0920:
0921:                private void invoke(int op) {
0922:                    // part of #33165 - done synchronously not invoking into EQ
0923:                    //SwingUtilities.invokeLater(new LR(op));
0924:                    new LR(op).run();
0925:                }
0926:
0927:                private void invoke(EnhancedChangeEvent ev) {
0928:                    // part of #33165 - done synchronously not invoking into EQ
0929:                    //SwingUtilities.invokeLater(new LR(ev));
0930:                    new LR(ev).run();
0931:                }
0932:
0933:                public void stateChanged(ChangeEvent ev) {
0934:                    invoke(REFRESH);
0935:                    invoke((EnhancedChangeEvent) ev);
0936:                }
0937:
0938:                public void removeUpdate(
0939:                        final javax.swing.event.DocumentEvent p0) {
0940:                    invoke(UNMARK);
0941:                }
0942:
0943:                public void insertUpdate(
0944:                        final javax.swing.event.DocumentEvent p0) {
0945:                    invoke(UNMARK);
0946:                }
0947:
0948:                public void changedUpdate(
0949:                        final javax.swing.event.DocumentEvent p0) {
0950:                }
0951:            }
0952:
0953:            /** Abstract implementation of {@link Line.Set}.
0954:             *  Defines
0955:             * ways to obtain a line set for documents following
0956:             * NetBeans conventions.
0957:             */
0958:            public static abstract class Set extends Line.Set {
0959:                /** listener on document changes, accessed from LazyLines */
0960:                final LineListener listener;
0961:
0962:                /** all lines in the set or null */
0963:                private List<Line> list;
0964:
0965:                /** Constructor.
0966:                 * @param doc document to work on
0967:                 */
0968:                public Set(StyledDocument doc) {
0969:                    this (doc, null);
0970:                }
0971:
0972:                Set(StyledDocument doc, CloneableEditorSupport support) {
0973:                    listener = new LineListener(doc, support);
0974:                }
0975:
0976:                /** Find the line given as parameter in list of all lines attached to this set
0977:                 * and if the line exist in the list, notify it about being edited. */
0978:                void linesChanged(int startLineNumber, int endLineNumber,
0979:                        DocumentEvent p0) {
0980:                    List changedLines = getLinesFromRange(startLineNumber,
0981:                            endLineNumber);
0982:                    StyledDocument doc = listener.support.getDocument();
0983:
0984:                    for (Iterator it = changedLines.iterator(); it.hasNext();) {
0985:                        Line line = (Line) it.next();
0986:
0987:                        line.firePropertyChange(Annotatable.PROP_TEXT, null,
0988:                                null);
0989:
0990:                        // revalidate all parts attached to this line
0991:                        // that they are still part of the line
0992:                        if (doc != null && line instanceof  DocumentLine) {
0993:                            ((DocumentLine) line).notifyChange(p0, this , doc);
0994:                        }
0995:                    }
0996:                }
0997:
0998:                /** Find the line given as parameter in list of all lines attached to this set
0999:                 * and if the line exist in the list, notify it about being moved. */
1000:                void linesMoved(int startLineNumber, int endLineNumber) {
1001:                    List movedLines = getLinesFromRange(startLineNumber,
1002:                            endLineNumber);
1003:
1004:                    for (Iterator it = movedLines.iterator(); it.hasNext();) {
1005:                        Line line = (Line) it.next();
1006:                        line.firePropertyChange(Line.PROP_LINE_NUMBER, null,
1007:                                null);
1008:
1009:                        // notify all parts attached to this line
1010:                        // that they were moved
1011:                        if (line instanceof  DocumentLine) {
1012:                            ((DocumentLine) line).notifyMove();
1013:                        }
1014:                    }
1015:                }
1016:
1017:                /** Gets the lines with line number whitin the range inclusive.
1018:                 * @return <code>List</code> of lines from range inclusive */
1019:                private List<Line> getLinesFromRange(int startLineNumber,
1020:                        int endLineNumber) {
1021:                    List<Line> linesInRange = new ArrayList<Line>(10);
1022:
1023:                    synchronized (findWeakHashMap()) {
1024:                        for (Line line : findWeakHashMap().keySet()) {
1025:                            int lineNumber = line.getLineNumber();
1026:
1027:                            if ((startLineNumber <= lineNumber)
1028:                                    && (lineNumber <= endLineNumber)) {
1029:                                linesInRange.add(line);
1030:                            }
1031:                        }
1032:                    }
1033:
1034:                    return linesInRange;
1035:                }
1036:
1037:                /* Returns an unmodifiable set of Lines sorted by their
1038:                 * line numbers that contains all lines holded by this
1039:                 * Line.Set.
1040:                 *
1041:                 * @return list of Line objects
1042:                 */
1043:                public synchronized List<? extends Line> getLines() {
1044:                    if (list == null) {
1045:                        list = new LazyLines(this );
1046:                    }
1047:
1048:                    return list;
1049:                }
1050:
1051:                /* Finder method that for the given line number finds right
1052:                 * Line object that represent as closely as possible the line number
1053:                 * in the time when the Line.Set has been created.
1054:                 *
1055:                 * @param line is a number of the line (text line) we want to acquire
1056:                 * @exception IndexOutOfBoundsException if <code>line</code> is invalid.
1057:                 */
1058:                public Line getOriginal(int line)
1059:                        throws IndexOutOfBoundsException {
1060:                    int newLine = listener.getLine(line);
1061:                    return safelyRegisterLine(createLine(offset(newLine)));
1062:                }
1063:
1064:                public int getOriginalLineNumber(Line line) {
1065:                    Line find = findLine(line);
1066:
1067:                    if (find != null) {
1068:                        return listener.getOld(find.getLineNumber());
1069:                    } else {
1070:                        return -1;
1071:                    }
1072:                }
1073:
1074:                /* Creates current line.
1075:                 *
1076:                 * @param line is a number of the line (text line) we want to acquire
1077:                 * @exception IndexOutOfBoundsException if <code>line</code> is invalid.
1078:                 */
1079:                public Line getCurrent(int line)
1080:                        throws IndexOutOfBoundsException {
1081:
1082:                    return safelyRegisterLine(createLine(offset(line)));
1083:                }
1084:
1085:                private int offset(int line) {
1086:                    StyledDocument doc = listener.support.getDocument();
1087:                    int offset = doc == null ? 0 : NbDocument.findLineOffset(
1088:                            doc, line);
1089:                    return offset;
1090:                }
1091:
1092:                /** Creates a {@link Line} for a given offset.
1093:                 * @param offset the beginning offset of the line
1094:                 * @return line object representing the line at this offset
1095:                 */
1096:                protected abstract Line createLine(int offset);
1097:
1098:                /** Registers line, but only after obtaining the lock of the document.
1099:                 * This is a fix to issue 37767 as this creates ordering of locks (first
1100:                 * of all obtain documentrenderer, then ask for any other locks like
1101:                 * Line.Set.lines.
1102:                 *
1103:                 * @param line line we want to register
1104:                 * @return the line or some line that already was registered
1105:                 */
1106:                private Line safelyRegisterLine(final Line line) {
1107:                    assert line != null;
1108:                    class DocumentRenderer implements  Runnable {
1109:                        public Line result;
1110:
1111:                        public void run() {
1112:                            result = DocumentLine.Set.super .registerLine(line);
1113:                        }
1114:                    }
1115:                    StyledDocument doc = listener.support.getDocument();
1116:                    DocumentRenderer renderer = new DocumentRenderer();
1117:                    if (doc != null) {
1118:                        doc.render(renderer);
1119:                    } else {
1120:                        renderer.run();
1121:                    }
1122:
1123:                    return renderer.result;
1124:                }
1125:            }
1126:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.