Source Code Cross Referenced for TextEdit.java in  » IDE-Eclipse » text » org » eclipse » text » edits » 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 Eclipse » text » org.eclipse.text.edits 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*******************************************************************************
0002:         * Copyright (c) 2000, 2006 IBM Corporation and others.
0003:         * All rights reserved. This program and the accompanying materials
0004:         * are made available under the terms of the Eclipse Public License v1.0
0005:         * which accompanies this distribution, and is available at
0006:         * http://www.eclipse.org/legal/epl-v10.html
0007:         *
0008:         * Contributors:
0009:         *     IBM Corporation - initial API and implementation
0010:         *******************************************************************************/package org.eclipse.text.edits;
0011:
0012:        import java.util.ArrayList;
0013:        import java.util.Collections;
0014:        import java.util.Comparator;
0015:        import java.util.Iterator;
0016:        import java.util.List;
0017:
0018:        import org.eclipse.core.runtime.Assert;
0019:
0020:        import org.eclipse.jface.text.BadLocationException;
0021:        import org.eclipse.jface.text.IDocument;
0022:        import org.eclipse.jface.text.IRegion;
0023:        import org.eclipse.jface.text.Region;
0024:
0025:        /**
0026:         * A text edit describes an elementary text manipulation operation. Edits are
0027:         * executed by applying them to a document (e.g. an instance of <code>IDocument
0028:         * </code>).
0029:         * <p>
0030:         * Text edits form a tree. Clients can navigate the tree upwards, from child to
0031:         * parent, as well as downwards. Newly created edits are un-parented. New edits
0032:         * are added to the tree by calling one of the <code>add</code> methods on a parent
0033:         * edit.
0034:         * </p>
0035:         * <p>
0036:         * An edit tree is well formed in the following sense:
0037:         * <ul>
0038:         *   <li>a parent edit covers all its children</li>
0039:         *   <li>children don't overlap</li>
0040:         *   <li>an edit with length 0 can't have any children</li>
0041:         * </ul>
0042:         * Any manipulation of the tree that violates one of the above requirements results
0043:         * in a <code>MalformedTreeException</code>.
0044:         * </p>
0045:         * <p>
0046:         * Insert edits are represented by an edit of length 0. If more than one insert
0047:         * edit exists at the same offset then the edits are executed in the order in which
0048:         * they have been added to a parent. The following code example:
0049:         * <pre>
0050:         *    IDocument document= new Document("org");
0051:         * 	  MultiTextEdit edit= new MultiTextEdit();
0052:         *    edit.addChild(new InsertEdit(0, "www."));
0053:         *    edit.addChild(new InsertEdit(0, "eclipse."));
0054:         *    edit.apply(document);
0055:         * </pre>
0056:         * therefore results in string: "www.eclipse.org".
0057:         * </p>
0058:         * <p>
0059:         * Text edits can be executed in a mode where the edit's region is updated to
0060:         * reflect the edit's position in the changed document. Region updating is enabled
0061:         * by default or can be requested by passing <code>UPDATE_REGIONS</code> to the
0062:         * {@link #apply(IDocument, int) apply(IDocument, int)} method. In the above example
0063:         * the region of the <code>InsertEdit(0, "eclipse.")</code> edit after executing
0064:         * the root edit is <code>[3, 8]</code>. If the region of an edit got deleted during
0065:         * change execution the region is set to <code>[-1, -1]</code> and the method {@link
0066:         * #isDeleted() isDeleted} returns <code>true</code>.
0067:         * </p>
0068:         * This class isn't intended to be subclassed outside of the edit framework. Clients
0069:         * are only allowed to subclass <code>MultiTextEdit</code>.
0070:         *
0071:         * @since 3.0
0072:         */
0073:        public abstract class TextEdit {
0074:
0075:            /**
0076:             * Flags indicating that neither <code>CREATE_UNDO</code> nor
0077:             * <code>UPDATE_REGIONS</code> is set.
0078:             */
0079:            public static final int NONE = 0;
0080:
0081:            /**
0082:             * Flags indicating that applying an edit tree to a document
0083:             * is supposed to create a corresponding undo edit. If not
0084:             * specified <code>null</code> is returned from method <code>
0085:             * apply</code>.
0086:             */
0087:            public static final int CREATE_UNDO = 1 << 0;
0088:
0089:            /**
0090:             * Flag indicating that the edit's region will be updated to
0091:             * reflect its position in the changed document. If not specified
0092:             * when applying an edit tree to a document the edit's region will
0093:             * be arbitrary. It is even not guaranteed that the tree is still
0094:             * well formed.
0095:             */
0096:            public static final int UPDATE_REGIONS = 1 << 1;
0097:
0098:            private static class InsertionComparator implements  Comparator {
0099:                public int compare(Object o1, Object o2)
0100:                        throws MalformedTreeException {
0101:                    TextEdit edit1 = (TextEdit) o1;
0102:                    TextEdit edit2 = (TextEdit) o2;
0103:
0104:                    int offset1 = edit1.getOffset();
0105:                    int length1 = edit1.getLength();
0106:
0107:                    int offset2 = edit2.getOffset();
0108:                    int length2 = edit2.getLength();
0109:
0110:                    if (offset1 == offset2 && length1 == 0 && length2 == 0) {
0111:                        return 0;
0112:                    }
0113:                    if (offset1 + length1 <= offset2) {
0114:                        return -1;
0115:                    }
0116:                    if (offset2 + length2 <= offset1) {
0117:                        return 1;
0118:                    }
0119:                    throw new MalformedTreeException(null, edit1,
0120:                            TextEditMessages.getString("TextEdit.overlapping")); //$NON-NLS-1$
0121:                }
0122:            }
0123:
0124:            private static final TextEdit[] EMPTY_ARRAY = new TextEdit[0];
0125:            private static final InsertionComparator INSERTION_COMPARATOR = new InsertionComparator();
0126:
0127:            private static final int DELETED_VALUE = -1;
0128:
0129:            private int fOffset;
0130:            private int fLength;
0131:
0132:            private TextEdit fParent;
0133:            private List fChildren;
0134:
0135:            int fDelta;
0136:
0137:            /**
0138:             * Create a new text edit. Parent is initialized to <code>
0139:             * null<code> and the edit doesn't have any children.
0140:             *
0141:             * @param offset the edit's offset
0142:             * @param length the edit's length
0143:             */
0144:            protected TextEdit(int offset, int length) {
0145:                Assert.isTrue(offset >= 0 && length >= 0);
0146:                fOffset = offset;
0147:                fLength = length;
0148:                fDelta = 0;
0149:            }
0150:
0151:            /**
0152:             * Copy constructor
0153:             *
0154:             * @param source the source to copy form
0155:             */
0156:            protected TextEdit(TextEdit source) {
0157:                fOffset = source.fOffset;
0158:                fLength = source.fLength;
0159:                fDelta = 0;
0160:            }
0161:
0162:            //---- Region management -----------------------------------------------
0163:
0164:            /**
0165:             * Returns the range that this edit is manipulating. The returned
0166:             * <code>IRegion</code> contains the edit's offset and length at
0167:             * the point in time when this call is made. Any subsequent changes
0168:             * to the edit's offset and length aren't reflected in the returned
0169:             * region object.
0170:             * <p>
0171:             * Creating a region for a deleted edit will result in an assertion
0172:             * failure.
0173:             *
0174:             * @return the manipulated region
0175:             */
0176:            public final IRegion getRegion() {
0177:                return new Region(getOffset(), getLength());
0178:            }
0179:
0180:            /**
0181:             * Returns the offset of the edit. An offset is a 0-based
0182:             * character index. Returns <code>-1</code> if the edit
0183:             * is marked as deleted.
0184:             *
0185:             * @return the offset of the edit
0186:             */
0187:            public int getOffset() {
0188:                return fOffset;
0189:            }
0190:
0191:            /**
0192:             * Returns the length of the edit. Returns <code>-1</code>
0193:             * if the edit is marked as deleted.
0194:             *
0195:             * @return the length of the edit
0196:             */
0197:            public int getLength() {
0198:                return fLength;
0199:            }
0200:
0201:            /**
0202:             * Returns the inclusive end position of this edit. The inclusive end
0203:             * position denotes the last character of the region manipulated by
0204:             * this edit. The returned value is the result of the following
0205:             * calculation:
0206:             * <pre>
0207:             *   getOffset() + getLength() - 1;
0208:             * <pre>
0209:             *
0210:             * @return the inclusive end position
0211:             */
0212:            public final int getInclusiveEnd() {
0213:                return getOffset() + getLength() - 1;
0214:            }
0215:
0216:            /**
0217:             * Returns the exclusive end position of this edit. The exclusive end
0218:             * position denotes the next character of the region manipulated by
0219:             * this edit. The returned value is the result of the following
0220:             * calculation:
0221:             * <pre>
0222:             *   getOffset() + getLength();
0223:             * </pre>
0224:             *
0225:             * @return the exclusive end position
0226:             */
0227:            public final int getExclusiveEnd() {
0228:                return getOffset() + getLength();
0229:            }
0230:
0231:            /**
0232:             * Returns whether this edit has been deleted or not.
0233:             *
0234:             * @return <code>true</code> if the edit has been
0235:             *  deleted; otherwise <code>false</code> is returned.
0236:             */
0237:            public final boolean isDeleted() {
0238:                return fOffset == DELETED_VALUE && fLength == DELETED_VALUE;
0239:            }
0240:
0241:            /**
0242:             * Move all offsets in the tree by the given delta. This node must be a
0243:             * root node. The resulting offsets must be greater or equal to zero.
0244:             *
0245:             * @param delta the delta
0246:             * @since 3.1
0247:             */
0248:            public final void moveTree(int delta) {
0249:                Assert.isTrue(fParent == null);
0250:                Assert.isTrue(getOffset() + delta >= 0);
0251:                internalMoveTree(delta);
0252:            }
0253:
0254:            /**
0255:             * Returns <code>true</code> if the edit covers the given edit
0256:             * <code>other</code>. It is up to the concrete text edit to
0257:             * decide if a edit of length zero can cover another edit.
0258:             *
0259:             * @param other the other edit
0260:             * @return <code>true<code> if the edit covers the other edit;
0261:             *  otherwise <code>false</code> is returned.
0262:             */
0263:            public boolean covers(TextEdit other) {
0264:                if (getLength() == 0 && !canZeroLengthCover())
0265:                    return false;
0266:
0267:                if (!other.isDefined())
0268:                    return true;
0269:
0270:                int this Offset = getOffset();
0271:                int otherOffset = other.getOffset();
0272:                return this Offset <= otherOffset
0273:                        && otherOffset + other.getLength() <= this Offset
0274:                                + getLength();
0275:            }
0276:
0277:            /**
0278:             * Returns <code>true</code> if an edit with length zero can cover
0279:             * another edit. Returns <code>false</code> otherwise.
0280:             *
0281:             * @return whether an edit of length zero can cover another edit
0282:             */
0283:            protected boolean canZeroLengthCover() {
0284:                return false;
0285:            }
0286:
0287:            /**
0288:             * Returns whether the region of this edit is defined or not.
0289:             *
0290:             * @return whether the region of this edit is defined or not
0291:             *
0292:             * @since 3.1
0293:             */
0294:            boolean isDefined() {
0295:                return true;
0296:            }
0297:
0298:            //---- parent and children management -----------------------------
0299:
0300:            /**
0301:             * Returns the edit's parent. The method returns <code>null</code>
0302:             * if this edit hasn't been add to another edit.
0303:             *
0304:             * @return the edit's parent
0305:             */
0306:            public final TextEdit getParent() {
0307:                return fParent;
0308:            }
0309:
0310:            /**
0311:             * Returns the root edit of the edit tree.
0312:             *
0313:             * @return the root edit of the edit tree
0314:             * @since 3.1
0315:             */
0316:            public final TextEdit getRoot() {
0317:                TextEdit result = this ;
0318:                while (result.fParent != null) {
0319:                    result = result.fParent;
0320:                }
0321:                return result;
0322:            }
0323:
0324:            /**
0325:             * Adds the given edit <code>child</code> to this edit.
0326:             *
0327:             * @param child the child edit to add
0328:             * @exception MalformedTreeException is thrown if the child
0329:             *  edit can't be added to this edit. This is the case if the child
0330:             *  overlaps with one of its siblings or if the child edit's region
0331:             *  isn't fully covered by this edit.
0332:             */
0333:            public final void addChild(TextEdit child)
0334:                    throws MalformedTreeException {
0335:                internalAdd(child);
0336:            }
0337:
0338:            /**
0339:             * Adds all edits in <code>edits</code> to this edit.
0340:             *
0341:             * @param edits the text edits to add
0342:             * @exception MalformedTreeException is thrown if one of
0343:             *  the given edits can't be added to this edit.
0344:             *
0345:             * @see #addChild(TextEdit)
0346:             */
0347:            public final void addChildren(TextEdit[] edits)
0348:                    throws MalformedTreeException {
0349:                for (int i = 0; i < edits.length; i++) {
0350:                    internalAdd(edits[i]);
0351:                }
0352:            }
0353:
0354:            /**
0355:             * Removes the edit specified by the given index from the list
0356:             * of children. Returns the child edit that was removed from
0357:             * the list of children. The parent of the returned edit is
0358:             * set to <code>null</code>.
0359:             *
0360:             * @param index the index of the edit to remove
0361:             * @return the removed edit
0362:             * @exception IndexOutOfBoundsException if the index
0363:             *  is out of range
0364:             */
0365:            public final TextEdit removeChild(int index) {
0366:                if (fChildren == null)
0367:                    throw new IndexOutOfBoundsException(
0368:                            "Index: " + index + " Size: 0"); //$NON-NLS-1$//$NON-NLS-2$
0369:                TextEdit result = (TextEdit) fChildren.remove(index);
0370:                result.internalSetParent(null);
0371:                if (fChildren.isEmpty())
0372:                    fChildren = null;
0373:                return result;
0374:            }
0375:
0376:            /**
0377:             * Removes the first occurrence of the given child from the list
0378:             * of children.
0379:             *
0380:             * @param child the child to be removed
0381:             * @return <code>true</code> if the edit contained the given
0382:             *  child; otherwise <code>false</code> is returned
0383:             */
0384:            public final boolean removeChild(TextEdit child) {
0385:                Assert.isNotNull(child);
0386:                if (fChildren == null)
0387:                    return false;
0388:                boolean result = fChildren.remove(child);
0389:                if (result) {
0390:                    child.internalSetParent(null);
0391:                    if (fChildren.isEmpty())
0392:                        fChildren = null;
0393:                }
0394:                return result;
0395:            }
0396:
0397:            /**
0398:             * Removes all child edits from and returns them. The parent
0399:             * of the removed edits is set to <code>null</code>.
0400:             *
0401:             * @return an array of the removed edits
0402:             */
0403:            public final TextEdit[] removeChildren() {
0404:                if (fChildren == null)
0405:                    return EMPTY_ARRAY;
0406:                int size = fChildren.size();
0407:                TextEdit[] result = new TextEdit[size];
0408:                for (int i = 0; i < size; i++) {
0409:                    result[i] = (TextEdit) fChildren.get(i);
0410:                    result[i].internalSetParent(null);
0411:                }
0412:                fChildren = null;
0413:                return result;
0414:            }
0415:
0416:            /**
0417:             * Returns <code>true</code> if this edit has children. Otherwise
0418:             * <code>false</code> is returned.
0419:             *
0420:             * @return <code>true</code> if this edit has children; otherwise
0421:             *  <code>false</code> is returned
0422:             */
0423:            public final boolean hasChildren() {
0424:                return fChildren != null && !fChildren.isEmpty();
0425:            }
0426:
0427:            /**
0428:             * Returns the edit's children. If the edit doesn't have any
0429:             * children an empty array is returned.
0430:             *
0431:             * @return the edit's children
0432:             */
0433:            public final TextEdit[] getChildren() {
0434:                if (fChildren == null)
0435:                    return EMPTY_ARRAY;
0436:                return (TextEdit[]) fChildren.toArray(new TextEdit[fChildren
0437:                        .size()]);
0438:            }
0439:
0440:            /**
0441:             * Returns the size of the managed children.
0442:             *
0443:             * @return the size of the children
0444:             */
0445:            public final int getChildrenSize() {
0446:                if (fChildren == null)
0447:                    return 0;
0448:                return fChildren.size();
0449:            }
0450:
0451:            /**
0452:             * Returns the text range spawned by the given array of text edits.
0453:             * The method requires that the given array contains at least one
0454:             * edit. If all edits passed are deleted the method returns <code>
0455:             * null</code>.
0456:             *
0457:             * @param edits an array of edits
0458:             * @return the text range spawned by the given array of edits or
0459:             *  <code>null</code> if all edits are marked as deleted
0460:             */
0461:            public static IRegion getCoverage(TextEdit[] edits) {
0462:                Assert.isTrue(edits != null && edits.length > 0);
0463:
0464:                int offset = Integer.MAX_VALUE;
0465:                int end = Integer.MIN_VALUE;
0466:                int deleted = 0;
0467:                for (int i = 0; i < edits.length; i++) {
0468:                    TextEdit edit = edits[i];
0469:                    if (edit.isDeleted()) {
0470:                        deleted++;
0471:                    } else {
0472:                        offset = Math.min(offset, edit.getOffset());
0473:                        end = Math.max(end, edit.getExclusiveEnd());
0474:                    }
0475:                }
0476:                if (edits.length == deleted)
0477:                    return null;
0478:
0479:                return new Region(offset, end - offset);
0480:            }
0481:
0482:            /*
0483:             * Hook called before this edit gets added to the passed
0484:             * parent.
0485:             */
0486:            void aboutToBeAdded(TextEdit parent) {
0487:            }
0488:
0489:            //---- Object methods ------------------------------------------------------
0490:
0491:            /**
0492:             * The <code>Edit</code> implementation of this <code>Object</code>
0493:             * method uses object identity (==).
0494:             *
0495:             * @param obj the other object
0496:             * @return <code>true</code> iff <code>this == obj</code>; otherwise
0497:             *  <code>false</code> is returned
0498:             *
0499:             * @see Object#equals(java.lang.Object)
0500:             */
0501:            public final boolean equals(Object obj) {
0502:                return this  == obj; // equivalent to Object.equals
0503:            }
0504:
0505:            /**
0506:             * The <code>Edit</code> implementation of this <code>Object</code>
0507:             * method calls uses <code>Object#hashCode()</code> to compute its
0508:             * hash code.
0509:             *
0510:             * @return the object's hash code value
0511:             *
0512:             * @see Object#hashCode()
0513:             */
0514:            public final int hashCode() {
0515:                return super .hashCode();
0516:            }
0517:
0518:            /*
0519:             * @see java.lang.Object#toString()
0520:             */
0521:            public String toString() {
0522:                StringBuffer buffer = new StringBuffer();
0523:                toStringWithChildren(buffer, 0);
0524:                return buffer.toString();
0525:            }
0526:
0527:            /**
0528:             * Adds the string representation of this text edit without
0529:             * children information to the given string buffer.
0530:             * 
0531:             * @param buffer	the string buffer
0532:             * @param indent	the indent level in number of spaces
0533:             * @since 3.3
0534:             */
0535:            void internalToString(StringBuffer buffer, int indent) {
0536:                for (int i = indent; i > 0; i--) {
0537:                    buffer.append("  "); //$NON-NLS-1$
0538:                }
0539:                buffer.append("{"); //$NON-NLS-1$
0540:                String name = getClass().getName();
0541:                int index = name.lastIndexOf('.');
0542:                if (index != -1) {
0543:                    buffer.append(name.substring(index + 1));
0544:                } else {
0545:                    buffer.append(name);
0546:                }
0547:                buffer.append("} "); //$NON-NLS-1$
0548:                if (isDeleted()) {
0549:                    buffer.append("[deleted]"); //$NON-NLS-1$
0550:                } else {
0551:                    buffer.append("["); //$NON-NLS-1$
0552:                    buffer.append(getOffset());
0553:                    buffer.append(","); //$NON-NLS-1$
0554:                    buffer.append(getLength());
0555:                    buffer.append("]"); //$NON-NLS-1$
0556:                }
0557:            }
0558:
0559:            /**
0560:             * Adds the string representation for this text edit 
0561:             * and its children to the given string buffer.
0562:             * 
0563:             * @param buffer	the string buffer
0564:             * @param indent	the indent level in number of spaces
0565:             * @since 3.3
0566:             */
0567:            private void toStringWithChildren(StringBuffer buffer, int indent) {
0568:                internalToString(buffer, indent);
0569:                if (fChildren != null) {
0570:                    for (Iterator iterator = fChildren.iterator(); iterator
0571:                            .hasNext();) {
0572:                        TextEdit child = (TextEdit) iterator.next();
0573:                        buffer.append('\n');
0574:                        child.toStringWithChildren(buffer, indent + 1);
0575:                    }
0576:                }
0577:            }
0578:
0579:            //---- Copying -------------------------------------------------------------
0580:
0581:            /**
0582:             * Creates a deep copy of the edit tree rooted at this
0583:             * edit.
0584:             *
0585:             * @return a deep copy of the edit tree
0586:             * @see #doCopy()
0587:             */
0588:            public final TextEdit copy() {
0589:                TextEditCopier copier = new TextEditCopier(this );
0590:                return copier.perform();
0591:            }
0592:
0593:            /**
0594:             * Creates and returns a copy of this edit. The copy method should be
0595:             * implemented in a way so that the copy can executed without causing
0596:             * any harm to the original edit. Implementors of this method are
0597:             * responsible for creating deep or shallow copies of referenced
0598:             * object to fulfill this requirement.
0599:             * <p>
0600:             * Implementers of this method should use the copy constructor <code>
0601:             * Edit#Edit(Edit source) to initialize the edit part of the copy.
0602:             * Implementors aren't responsible to actually copy the children or
0603:             * to set the right parent.
0604:             * <p>
0605:             * This method <b>should not be called</b> from outside the framework.
0606:             * Please use <code>copy</code> to create a copy of a edit tree.
0607:             *
0608:             * @return a copy of this edit.
0609:             * @see #copy()
0610:             * @see #postProcessCopy(TextEditCopier)
0611:             * @see TextEditCopier
0612:             */
0613:            protected abstract TextEdit doCopy();
0614:
0615:            /**
0616:             * This method is called on every edit of the copied tree to do some
0617:             * post-processing like connected an edit to a different edit in the tree.
0618:             * <p>
0619:             * This default implementation does nothing
0620:             *
0621:             * @param copier the copier that manages a map between original and
0622:             *  copied edit.
0623:             * @see TextEditCopier
0624:             */
0625:            protected void postProcessCopy(TextEditCopier copier) {
0626:            }
0627:
0628:            //---- Visitor support -------------------------------------------------
0629:
0630:            /**
0631:             * Accepts the given visitor on a visit of the current edit.
0632:             *
0633:             * @param visitor the visitor object
0634:             * @exception IllegalArgumentException if the visitor is null
0635:             */
0636:            public final void accept(TextEditVisitor visitor) {
0637:                Assert.isNotNull(visitor);
0638:                // begin with the generic pre-visit
0639:                visitor.preVisit(this );
0640:                // dynamic dispatch to internal method for type-specific visit/endVisit
0641:                accept0(visitor);
0642:                // end with the generic post-visit
0643:                visitor.postVisit(this );
0644:            }
0645:
0646:            /**
0647:             * Accepts the given visitor on a type-specific visit of the current edit.
0648:             * This method must be implemented in all concrete text edits.
0649:             * <p>
0650:             * General template for implementation on each concrete TextEdit class:
0651:             * <pre>
0652:             * <code>
0653:             * boolean visitChildren= visitor.visit(this);
0654:             * if (visitChildren) {
0655:             *    acceptChildren(visitor);
0656:             * }
0657:             * </code>
0658:             * </pre>
0659:             * Note that the caller (<code>accept</code>) takes care of invoking
0660:             * <code>visitor.preVisit(this)</code> and <code>visitor.postVisit(this)</code>.
0661:             * </p>
0662:             *
0663:             * @param visitor the visitor object
0664:             */
0665:            protected abstract void accept0(TextEditVisitor visitor);
0666:
0667:            /**
0668:             * Accepts the given visitor on the edits children.
0669:             * <p>
0670:             * This method must be used by the concrete implementations of
0671:             * <code>accept</code> to traverse list-values properties; it
0672:             * encapsulates the proper handling of on-the-fly changes to the list.
0673:             * </p>
0674:             *
0675:             * @param visitor the visitor object
0676:             */
0677:            protected final void acceptChildren(TextEditVisitor visitor) {
0678:                if (fChildren == null)
0679:                    return;
0680:                Iterator iterator = fChildren.iterator();
0681:                while (iterator.hasNext()) {
0682:                    TextEdit curr = (TextEdit) iterator.next();
0683:                    curr.accept(visitor);
0684:                }
0685:            }
0686:
0687:            //---- Execution -------------------------------------------------------
0688:
0689:            /**
0690:             * Applies the edit tree rooted by this edit to the given document. To check
0691:             * if the edit tree can be applied to the document either catch <code>
0692:             * MalformedTreeException</code> or use <code>TextEditProcessor</code> to
0693:             * execute an edit tree.
0694:             *
0695:             * @param document the document to be manipulated
0696:             * @param style flags controlling the execution of the edit tree. Valid
0697:             *  flags are: <code>CREATE_UNDO</code> and </code>UPDATE_REGIONS</code>.
0698:             * @return a undo edit, if <code>CREATE_UNDO</code> is specified. Otherwise
0699:             *  <code>null</code> is returned.
0700:             *
0701:             * @exception MalformedTreeException is thrown if the tree isn't
0702:             *  in a valid state. This exception is thrown before any edit
0703:             *  is executed. So the document is still in its original state.
0704:             * @exception BadLocationException is thrown if one of the edits
0705:             *  in the tree can't be executed. The state of the document is
0706:             *  undefined if this exception is thrown.
0707:             *
0708:             * @see TextEditProcessor#performEdits()
0709:             */
0710:            public final UndoEdit apply(IDocument document, int style)
0711:                    throws MalformedTreeException, BadLocationException {
0712:                try {
0713:                    TextEditProcessor processor = new TextEditProcessor(
0714:                            document, this , style);
0715:                    return processor.performEdits();
0716:                } finally {
0717:                    // disconnect from text edit processor
0718:                    fParent = null;
0719:                }
0720:            }
0721:
0722:            /**
0723:             * Applies the edit tree rooted by this edit to the given document. This
0724:             * method is a convenience method for <code>apply(document, CREATE_UNDO | UPDATE_REGIONS)
0725:             * </code>
0726:             *
0727:             * @param document the document to which to apply this edit
0728:             * @return a undo edit, if <code>CREATE_UNDO</code> is specified. Otherwise
0729:             *  <code>null</code> is returned.
0730:             * @exception MalformedTreeException is thrown if the tree isn't
0731:             *  in a valid state. This exception is thrown before any edit
0732:             *  is executed. So the document is still in its original state.
0733:             * @exception BadLocationException is thrown if one of the edits
0734:             *  in the tree can't be executed. The state of the document is
0735:             *  undefined if this exception is thrown.
0736:             * @see #apply(IDocument, int)
0737:             */
0738:            public final UndoEdit apply(IDocument document)
0739:                    throws MalformedTreeException, BadLocationException {
0740:                return apply(document, CREATE_UNDO | UPDATE_REGIONS);
0741:            }
0742:
0743:            UndoEdit dispatchPerformEdits(TextEditProcessor processor)
0744:                    throws BadLocationException {
0745:                return processor.executeDo();
0746:            }
0747:
0748:            void dispatchCheckIntegrity(TextEditProcessor processor)
0749:                    throws MalformedTreeException {
0750:                processor.checkIntegrityDo();
0751:            }
0752:
0753:            //---- internal state accessors ----------------------------------------------------------
0754:
0755:            void internalSetParent(TextEdit parent) {
0756:                if (parent != null)
0757:                    Assert.isTrue(fParent == null);
0758:                fParent = parent;
0759:            }
0760:
0761:            void internalSetOffset(int offset) {
0762:                Assert.isTrue(offset >= 0);
0763:                fOffset = offset;
0764:            }
0765:
0766:            void internalSetLength(int length) {
0767:                Assert.isTrue(length >= 0);
0768:                fLength = length;
0769:            }
0770:
0771:            List internalGetChildren() {
0772:                return fChildren;
0773:            }
0774:
0775:            void internalSetChildren(List children) {
0776:                fChildren = children;
0777:            }
0778:
0779:            void internalAdd(TextEdit child) throws MalformedTreeException {
0780:                child.aboutToBeAdded(this );
0781:                if (child.isDeleted())
0782:                    throw new MalformedTreeException(this , child,
0783:                            TextEditMessages.getString("TextEdit.deleted_edit")); //$NON-NLS-1$
0784:                if (!covers(child))
0785:                    throw new MalformedTreeException(this , child,
0786:                            TextEditMessages
0787:                                    .getString("TextEdit.range_outside")); //$NON-NLS-1$
0788:                if (fChildren == null) {
0789:                    fChildren = new ArrayList(2);
0790:                }
0791:                int index = computeInsertionIndex(child);
0792:                fChildren.add(index, child);
0793:                child.internalSetParent(this );
0794:            }
0795:
0796:            private int computeInsertionIndex(TextEdit edit)
0797:                    throws MalformedTreeException {
0798:                int size = fChildren.size();
0799:                if (size == 0)
0800:                    return 0;
0801:                int lastIndex = size - 1;
0802:                TextEdit last = (TextEdit) fChildren.get(lastIndex);
0803:                if (last.getExclusiveEnd() <= edit.getOffset())
0804:                    return size;
0805:                try {
0806:
0807:                    int index = Collections.binarySearch(fChildren, edit,
0808:                            INSERTION_COMPARATOR);
0809:
0810:                    if (index < 0)
0811:                        // edit is not in fChildren
0812:                        return -index - 1;
0813:
0814:                    // edit is already in fChildren
0815:                    // make sure that multiple insertion points at the same offset are inserted last.
0816:                    while (index < lastIndex
0817:                            && INSERTION_COMPARATOR.compare(fChildren
0818:                                    .get(index), fChildren.get(index + 1)) == 0)
0819:                        index++;
0820:
0821:                    return index + 1;
0822:
0823:                } catch (MalformedTreeException e) {
0824:                    e.setParent(this );
0825:                    throw e;
0826:                }
0827:            }
0828:
0829:            //---- Offset & Length updating -------------------------------------------------
0830:
0831:            /**
0832:             * Adjusts the edits offset according to the given
0833:             * delta. This method doesn't update any children.
0834:             *
0835:             * @param delta the delta of the text replace operation
0836:             */
0837:            void adjustOffset(int delta) {
0838:                if (isDeleted())
0839:                    return;
0840:                fOffset += delta;
0841:                Assert.isTrue(fOffset >= 0);
0842:            }
0843:
0844:            /**
0845:             * Adjusts the edits length according to the given
0846:             * delta. This method doesn't update any children.
0847:             *
0848:             * @param delta the delta of the text replace operation
0849:             */
0850:            void adjustLength(int delta) {
0851:                if (isDeleted())
0852:                    return;
0853:                fLength += delta;
0854:                Assert.isTrue(fLength >= 0);
0855:            }
0856:
0857:            /**
0858:             * Marks the edit as deleted. This method doesn't update
0859:             * any children.
0860:             */
0861:            void markAsDeleted() {
0862:                fOffset = DELETED_VALUE;
0863:                fLength = DELETED_VALUE;
0864:            }
0865:
0866:            //---- Edit processing ----------------------------------------------
0867:
0868:            /**
0869:             * Traverses the edit tree to perform the consistency check.
0870:             *
0871:             * @param processor the text edit processor
0872:             * @param document the document to be manipulated
0873:             * @param sourceEdits the list of source edits to be performed before
0874:             *  the actual tree is applied to the document
0875:             *
0876:             * @return the number of indirect move or copy target edit children
0877:             */
0878:            int traverseConsistencyCheck(TextEditProcessor processor,
0879:                    IDocument document, List sourceEdits) {
0880:                int result = 0;
0881:                if (fChildren != null) {
0882:                    for (int i = fChildren.size() - 1; i >= 0; i--) {
0883:                        TextEdit child = (TextEdit) fChildren.get(i);
0884:                        result = Math.max(result, child
0885:                                .traverseConsistencyCheck(processor, document,
0886:                                        sourceEdits));
0887:                    }
0888:                }
0889:                if (processor.considerEdit(this )) {
0890:                    performConsistencyCheck(processor, document);
0891:                }
0892:                return result;
0893:            }
0894:
0895:            void performConsistencyCheck(TextEditProcessor processor,
0896:                    IDocument document) {
0897:            }
0898:
0899:            void traverseSourceComputation(TextEditProcessor processor,
0900:                    IDocument document) {
0901:            }
0902:
0903:            void performSourceComputation(TextEditProcessor processor,
0904:                    IDocument document) {
0905:            }
0906:
0907:            int traverseDocumentUpdating(TextEditProcessor processor,
0908:                    IDocument document) throws BadLocationException {
0909:                int delta = 0;
0910:                if (fChildren != null) {
0911:                    for (int i = fChildren.size() - 1; i >= 0; i--) {
0912:                        TextEdit child = (TextEdit) fChildren.get(i);
0913:                        delta += child.traverseDocumentUpdating(processor,
0914:                                document);
0915:                        childDocumentUpdated();
0916:                    }
0917:                }
0918:                if (processor.considerEdit(this )) {
0919:                    if (delta != 0)
0920:                        adjustLength(delta);
0921:                    int r = performDocumentUpdating(document);
0922:                    if (r != 0)
0923:                        adjustLength(r);
0924:                    delta += r;
0925:                }
0926:                return delta;
0927:            }
0928:
0929:            /**
0930:             * Hook method called when the document updating of a child edit has been
0931:             * completed. When a client calls {@link #apply(IDocument)} or
0932:             * {@link #apply(IDocument, int)} this method is called
0933:             * {@link #getChildrenSize()} times.
0934:             * <p>
0935:             * May be overridden by subclasses of {@link MultiTextEdit}.
0936:             *
0937:             * @since 3.1
0938:             */
0939:            protected void childDocumentUpdated() {
0940:            }
0941:
0942:            abstract int performDocumentUpdating(IDocument document)
0943:                    throws BadLocationException;
0944:
0945:            int traverseRegionUpdating(TextEditProcessor processor,
0946:                    IDocument document, int accumulatedDelta, boolean delete) {
0947:                performRegionUpdating(accumulatedDelta, delete);
0948:                if (fChildren != null) {
0949:                    boolean childDelete = delete || deleteChildren();
0950:                    for (Iterator iter = fChildren.iterator(); iter.hasNext();) {
0951:                        TextEdit child = (TextEdit) iter.next();
0952:                        accumulatedDelta = child.traverseRegionUpdating(
0953:                                processor, document, accumulatedDelta,
0954:                                childDelete);
0955:                        childRegionUpdated();
0956:                    }
0957:                }
0958:                return accumulatedDelta + fDelta;
0959:            }
0960:
0961:            /**
0962:             * Hook method called when the region updating of a child edit has been
0963:             * completed. When a client calls {@link #apply(IDocument)} this method is
0964:             * called {@link #getChildrenSize()} times. When calling
0965:             * {@link #apply(IDocument, int)} this method is called
0966:             * {@link #getChildrenSize()} times, when the style parameter contains the
0967:             * {@link #UPDATE_REGIONS} flag.
0968:             * <p>
0969:             * May be overridden by subclasses of {@link MultiTextEdit}.
0970:             *
0971:             * @since 3.1
0972:             */
0973:            protected void childRegionUpdated() {
0974:            }
0975:
0976:            void performRegionUpdating(int accumulatedDelta, boolean delete) {
0977:                if (delete)
0978:                    markAsDeleted();
0979:                else
0980:                    adjustOffset(accumulatedDelta);
0981:            }
0982:
0983:            abstract boolean deleteChildren();
0984:
0985:            void internalMoveTree(int delta) {
0986:                adjustOffset(delta);
0987:                if (fChildren != null) {
0988:                    for (Iterator iter = fChildren.iterator(); iter.hasNext();) {
0989:                        ((TextEdit) iter.next()).internalMoveTree(delta);
0990:                    }
0991:                }
0992:            }
0993:
0994:            void deleteTree() {
0995:                markAsDeleted();
0996:                if (fChildren != null) {
0997:                    for (Iterator iter = fChildren.iterator(); iter.hasNext();) {
0998:                        TextEdit child = (TextEdit) iter.next();
0999:                        child.deleteTree();
1000:                    }
1001:                }
1002:            }
1003:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.