Source Code Cross Referenced for DefaultStyledDocument.java in  » Apache-Harmony-Java-SE » javax-package » javax » swing » 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 » Apache Harmony Java SE » javax package » javax.swing.text 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         *  Licensed to the Apache Software Foundation (ASF) under one or more
0003:         *  contributor license agreements.  See the NOTICE file distributed with
0004:         *  this work for additional information regarding copyright ownership.
0005:         *  The ASF licenses this file to You under the Apache License, Version 2.0
0006:         *  (the "License"); you may not use this file except in compliance with
0007:         *  the License.  You may obtain a copy of the License at
0008:         *
0009:         *     http://www.apache.org/licenses/LICENSE-2.0
0010:         *
0011:         *  Unless required by applicable law or agreed to in writing, software
0012:         *  distributed under the License is distributed on an "AS IS" BASIS,
0013:         *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014:         *  See the License for the specific language governing permissions and
0015:         *  limitations under the License.
0016:         */
0017:        /**
0018:         * @author Alexey A. Ivanov
0019:         * @version $Revision$
0020:         */package javax.swing.text;
0021:
0022:        import java.awt.Color;
0023:        import java.awt.Font;
0024:        import java.io.IOException;
0025:        import java.io.ObjectInputStream;
0026:        import java.io.ObjectOutputStream;
0027:        import java.io.Serializable;
0028:        import java.util.ArrayList;
0029:        import java.util.Enumeration;
0030:        import java.util.LinkedList;
0031:        import java.util.List;
0032:        import java.util.Stack;
0033:
0034:        import javax.swing.event.ChangeEvent;
0035:        import javax.swing.event.ChangeListener;
0036:        import javax.swing.event.DocumentListener;
0037:        import javax.swing.event.UndoableEditEvent;
0038:        import javax.swing.event.DocumentEvent.EventType;
0039:        import javax.swing.undo.AbstractUndoableEdit;
0040:        import javax.swing.undo.UndoableEdit;
0041:
0042:        import org.apache.harmony.x.swing.internal.nls.Messages;
0043:
0044:        public class DefaultStyledDocument extends AbstractDocument implements 
0045:                StyledDocument {
0046:
0047:            public static class AttributeUndoableEdit extends
0048:                    AbstractUndoableEdit {
0049:                protected AttributeSet copy;
0050:                protected Element element;
0051:                protected boolean isReplacing;
0052:                protected AttributeSet newAttributes;
0053:
0054:                public AttributeUndoableEdit(final Element element,
0055:                        final AttributeSet newAttributes,
0056:                        final boolean isReplacing) {
0057:                    this .element = element;
0058:                    this .newAttributes = newAttributes;
0059:                    this .isReplacing = isReplacing;
0060:                    this .copy = element.getAttributes().copyAttributes();
0061:                }
0062:
0063:                public void redo() {
0064:                    final AbstractElement elem = (AbstractElement) element;
0065:                    if (isReplacing) {
0066:                        elem.removeAttributes(elem);
0067:                    }
0068:                    elem.addAttributes(newAttributes);
0069:                }
0070:
0071:                public void undo() {
0072:                    final AbstractElement elem = (AbstractElement) element;
0073:                    elem.removeAttributes(newAttributes);
0074:                    elem.addAttributes(copy);
0075:                }
0076:            }
0077:
0078:            public class ElementBuffer implements  Serializable {
0079:                private final Element root;
0080:                private transient DefaultDocumentEvent event;
0081:                private transient int offset;
0082:                private transient int length;
0083:                private transient ChangeDesc current;
0084:
0085:                private transient Stack changeStack;
0086:                private transient List changes;
0087:                private transient boolean create;
0088:                private transient Element tail;
0089:
0090:                public ElementBuffer(final Element root) {
0091:                    this .root = root;
0092:                    initChangeLists();
0093:                }
0094:
0095:                public Element getRootElement() {
0096:                    return root;
0097:                }
0098:
0099:                public void insert(final int offset, final int length,
0100:                        final ElementSpec[] spec,
0101:                        final DefaultDocumentEvent event) {
0102:                    prepare(offset, length, event);
0103:
0104:                    insertUpdate(spec);
0105:
0106:                    collectEdits();
0107:                }
0108:
0109:                public void remove(final int offset, final int length,
0110:                        final DefaultDocumentEvent event) {
0111:                    prepare(offset, length, event);
0112:
0113:                    removeUpdate();
0114:
0115:                    applyEdits();
0116:                    collectEdits();
0117:                }
0118:
0119:                public void change(final int offset, final int length,
0120:                        final DefaultDocumentEvent event) {
0121:                    prepare(offset, length, event);
0122:
0123:                    changeUpdate();
0124:
0125:                    applyEdits();
0126:                    collectEdits();
0127:                }
0128:
0129:                public Element clone(final Element parent, final Element clonee) {
0130:                    if (clonee.isLeaf()) {
0131:                        return createLeafElement(parent,
0132:                                clonee.getAttributes(),
0133:                                clonee.getStartOffset(), clonee.getEndOffset());
0134:                    }
0135:                    BranchElement result = (BranchElement) createBranchElement(
0136:                            parent, clonee.getAttributes());
0137:                    final int count = clonee.getElementCount();
0138:                    if (count > 0) {
0139:                        Element[] children = new Element[count];
0140:                        for (int i = 0; i < count; i++) {
0141:                            children[i] = clone(result, clonee.getElement(i));
0142:                        }
0143:                        result.replace(0, 0, children);
0144:                    }
0145:                    return result;
0146:                }
0147:
0148:                protected void insertUpdate(final ElementSpec[] spec) {
0149:                    // Find the deepest branch
0150:                    Element branch = root;
0151:                    do {
0152:                        changeStack.push(new ChangeDesc(branch));
0153:                        branch = branch.getElement(branch
0154:                                .getElementIndex(offset));
0155:                    } while (!branch.isLeaf());
0156:
0157:                    current = (ChangeDesc) changeStack.peek();
0158:
0159:                    performSpecs(spec);
0160:                    leaveParagraph();
0161:                }
0162:
0163:                protected void removeUpdate() {
0164:                    final int endOffset = offset + length;
0165:                    final Element startLeaf = getCharacterElement(offset);
0166:                    final Element startBranch = startLeaf.getParentElement();
0167:
0168:                    final Element endLeaf = endOffset == startLeaf
0169:                            .getEndOffset()
0170:                            && endOffset < startBranch.getEndOffset() ? startLeaf
0171:                            : getCharacterElement(endOffset);
0172:                    final Element endBranch = endLeaf.getParentElement();
0173:
0174:                    if (startLeaf == endLeaf) {
0175:                        if (startLeaf.getStartOffset() == offset
0176:                                && endOffset == startLeaf.getEndOffset()) {
0177:
0178:                            current = new ChangeDesc(startBranch, offset);
0179:                            current.removed.add(startLeaf);
0180:                            changes.add(current);
0181:                        }
0182:                    } else if (startBranch == endBranch) {
0183:                        final int index = startBranch.getElementIndex(offset);
0184:                        current = new ChangeDesc(startBranch);
0185:                        for (int i = index; i < startBranch.getElementCount(); i++) {
0186:                            final Element child = startBranch.getElement(i);
0187:                            if (offset <= child.getStartOffset()
0188:                                    && child.getEndOffset() <= endOffset) {
0189:
0190:                                current.setChildIndex(i);
0191:                                current.removed.add(child);
0192:                            }
0193:                            if (endOffset < child.getEndOffset()) {
0194:                                break;
0195:                            }
0196:                        }
0197:
0198:                        changes.add(current);
0199:                    } else {
0200:                        final BranchElement parent = (BranchElement) startBranch
0201:                                .getParentElement();
0202:                        if (parent != null) {
0203:                            current = new ChangeDesc(parent, offset);
0204:
0205:                            BranchElement branch = (BranchElement) createBranchElement(
0206:                                    parent, startBranch.getAttributes());
0207:                            List children = new LinkedList();
0208:
0209:                            // Copy elements from startBranch
0210:                            int index = startBranch.getElementIndex(offset);
0211:                            if (startBranch.getElement(index).getStartOffset() < offset) {
0212:                                ++index;
0213:                            }
0214:                            for (int i = 0; i < index; i++) {
0215:                                children.add(clone(branch, startBranch
0216:                                        .getElement(i)));
0217:                            }
0218:
0219:                            // Copy elements from endBranch
0220:                            index = endBranch.getElementIndex(endOffset);
0221:                            for (int i = index; i < endBranch.getElementCount(); i++) {
0222:                                children.add(clone(branch, endBranch
0223:                                        .getElement(i)));
0224:                            }
0225:
0226:                            index = parent.getElementIndex(endOffset);
0227:                            for (int i = current.getChildIndex(); i <= index; i++) {
0228:                                current.removeChildElement(i);
0229:                            }
0230:                            current.added.add(branch);
0231:
0232:                            branch.replace(0, 0, listToElementArray(children));
0233:                        } else {
0234:                            current = new ChangeDesc(startBranch, offset);
0235:
0236:                            // Copy elements from endBranch
0237:                            int index = endBranch.getElementIndex(endOffset);
0238:                            for (int i = index; i < endBranch.getElementCount(); i++) {
0239:                                current.added.add(clone(startBranch, endBranch
0240:                                        .getElement(i)));
0241:                            }
0242:
0243:                            // Copy elements from startBranch
0244:                            int startIndex = startBranch
0245:                                    .getElementIndex(offset);
0246:                            int endIndex = startBranch
0247:                                    .getElementIndex(endOffset);
0248:                            for (int i = startIndex; i <= endIndex; i++) {
0249:                                current.removeChildElement(i);
0250:                            }
0251:                            current.setChildIndex(startIndex);
0252:
0253:                            current.apply();
0254:                        }
0255:
0256:                        changes.add(current);
0257:                    }
0258:                }
0259:
0260:                protected void changeUpdate() {
0261:                    final int endOffset = offset + length;
0262:                    final Element startLeaf = getCharacterElement(offset);
0263:                    final Element endLeaf = getCharacterElement(endOffset);
0264:
0265:                    if (startLeaf.getStartOffset() == offset
0266:                            && endOffset == startLeaf.getEndOffset()) {
0267:                        return;
0268:                    }
0269:
0270:                    if (startLeaf == endLeaf) {
0271:                        current = new ChangeDesc(startLeaf.getParentElement(),
0272:                                offset);
0273:                        current.splitLeafElement(startLeaf, offset, endOffset,
0274:                                true, startLeaf.getAttributes());
0275:
0276:                        changes.add(current);
0277:                    } else {
0278:                        // Break the startLeaf
0279:                        int start = startLeaf.getStartOffset();
0280:                        int end = startLeaf.getEndOffset();
0281:
0282:                        if (start < offset) {
0283:                            current = new ChangeDesc(startLeaf
0284:                                    .getParentElement(), offset);
0285:                            current.splitLeafElement(startLeaf, offset);
0286:                            changes.add(current);
0287:                        }
0288:
0289:                        // Break the endLeaf
0290:                        start = endLeaf.getStartOffset();
0291:                        end = endLeaf.getEndOffset();
0292:
0293:                        if (start < endOffset && endOffset < end) {
0294:                            final boolean sameParents = current != null
0295:                                    && current.element == endLeaf
0296:                                            .getParentElement();
0297:                            if (!sameParents) {
0298:                                current = new ChangeDesc(endLeaf
0299:                                        .getParentElement(), endOffset);
0300:                            } else {
0301:                                final int endIndex = current
0302:                                        .getChildIndexAtOffset(endOffset);
0303:                                for (int i = current.getChildIndex() + 1; i < endIndex; i++) {
0304:
0305:                                    final Element child = current
0306:                                            .getChildElement(i);
0307:                                    current.removed.add(child);
0308:                                    current.added.add(child);
0309:                                }
0310:                            }
0311:
0312:                            current.splitLeafElement(endLeaf, endOffset);
0313:
0314:                            if (!sameParents) {
0315:                                changes.add(current);
0316:                            }
0317:                        }
0318:                    }
0319:                }
0320:
0321:                final void create(final ElementSpec[] specs,
0322:                        final DefaultDocumentEvent event) {
0323:                    prepare(event.getOffset(), event.getLength(), event);
0324:                    create = true;
0325:
0326:                    // Remove all elements from the only paragraph
0327:                    current = new ChangeDesc(getParagraphElement(0));
0328:                    current.setChildIndex(0);
0329:                    current.createLeafElement(current.getChildElement(0)
0330:                            .getAttributes(), length, length + 1);
0331:                    for (int i = 0; i < current.element.getElementCount(); i++) {
0332:                        current.removeChildElement(i);
0333:                    }
0334:                    current.apply();
0335:                    changes.add(current);
0336:                    current = null;
0337:
0338:                    performSpecs(specs);
0339:                    leaveParagraph();
0340:
0341:                    collectEdits();
0342:                }
0343:
0344:                private void performSpecs(final ElementSpec[] spec)
0345:                        throws Error {
0346:                    for (int i = 0; i < spec.length; i++) {
0347:                        switch (spec[i].getType()) {
0348:                        case ElementSpec.ContentType:
0349:                            insertContent(spec[i]);
0350:                            break;
0351:
0352:                        case ElementSpec.EndTagType:
0353:                            insertEndTag();
0354:                            break;
0355:
0356:                        case ElementSpec.StartTagType:
0357:                            insertStartTag(spec[i]);
0358:                            break;
0359:
0360:                        default:
0361:                            throw new Error(Messages.getString("swing.err.12")); //$NON-NLS-1$
0362:                        }
0363:                    }
0364:                }
0365:
0366:                private void applyEdits() {
0367:                    for (int i = 0; i < changes.size(); i++) {
0368:                        final ChangeDesc desc = (ChangeDesc) changes.get(i);
0369:                        desc.apply();
0370:                    }
0371:                }
0372:
0373:                private void collectEdits() {
0374:                    while (!changeStack.empty()) {
0375:                        ChangeDesc desc = (ChangeDesc) changeStack.pop();
0376:                        if (!desc.isEmpty()) {
0377:                            changes.add(desc);
0378:                        }
0379:                    }
0380:
0381:                    for (int i = 0; i < changes.size(); i++) {
0382:                        final ChangeDesc desc = (ChangeDesc) changes.get(i);
0383:                        if (!desc.isEmpty()) {
0384:                            event.addEdit(desc.toElementEdit());
0385:                        }
0386:                    }
0387:                    changes.clear();
0388:
0389:                    clear();
0390:                }
0391:
0392:                private void clear() {
0393:                    event = null;
0394:                    current = null;
0395:                }
0396:
0397:                private void insertContent(final ElementSpec spec) {
0398:                    switch (spec.getDirection()) {
0399:                    case ElementSpec.OriginateDirection:
0400:                        insertContentOriginate(spec);
0401:                        break;
0402:
0403:                    case ElementSpec.JoinNextDirection:
0404:                        insertContentJoinNext(spec);
0405:                        break;
0406:
0407:                    case ElementSpec.JoinPreviousDirection:
0408:                        break;
0409:
0410:                    case ElementSpec.JoinFractureDirection:
0411:                        insertContentOriginate(spec);
0412:                        break;
0413:                    }
0414:                    offset += spec.getLength();
0415:                    length -= spec.getLength();
0416:                }
0417:
0418:                private void insertContentOriginate(final ElementSpec spec) {
0419:                    final AttributeSet specAttr = spec.getAttributes();
0420:                    if (current.element.getElementCount() == 0) {
0421:                        current.setChildIndex(0);
0422:                        current.createLeafElement(specAttr, offset, offset
0423:                                + spec.length);
0424:                    } else {
0425:                        current.setChildIndexByOffset(offset);
0426:                        final Element leafToRemove = current.getCurrentChild();
0427:                        if (offset == 0 && leafToRemove.isLeaf()) {
0428:                            current.removed.add(leafToRemove);
0429:                            current.createLeafElement(specAttr, offset, offset
0430:                                    + spec.length);
0431:                            current.createLeafElement(leafToRemove
0432:                                    .getAttributes(), offset + length,
0433:                                    leafToRemove.getEndOffset());
0434:                            tail = current.getLastAddedElement();
0435:                            current.added.remove(tail);
0436:                        } else if (offset == event.getOffset()
0437:                                && leafToRemove.getStartOffset() < offset
0438:                                && offset < leafToRemove.getEndOffset()) {
0439:                            if (leafToRemove.isLeaf()) {
0440:                                current.splitLeafElement(leafToRemove, offset,
0441:                                        offset + spec.length, offset + length,
0442:                                        true, specAttr);
0443:                                tail = current.getLastAddedElement();
0444:                                current.added.remove(tail);
0445:                            } else {
0446:                                tail = splitBranch(leafToRemove);
0447:                                current.createLeafElement(specAttr, offset,
0448:                                        offset + spec.length);
0449:                                current.childIndex = current.getChildIndex() + 1;
0450:                            }
0451:                        } else {
0452:                            current.createLeafElement(specAttr, offset, offset
0453:                                    + spec.length);
0454:                            if (offset >= current.element.getEndOffset()
0455:                                    && current.getChildIndex() < current.element
0456:                                            .getElementCount()) {
0457:                                current.childIndex = current.getChildIndex() + 1;
0458:                            }
0459:                        }
0460:                    }
0461:                }
0462:
0463:                private void insertContentJoinNext(final ElementSpec spec) {
0464:                    current.setChildIndexByOffset(offset);
0465:                    final Element leaf = current.getCurrentChild();
0466:                    if (leaf.getStartOffset() >= offset) {
0467:                        current.removed.add(leaf);
0468:                        current.createLeafElement(leaf.getAttributes(), offset,
0469:                                leaf.getEndOffset());
0470:                    } else {
0471:                        final Element next = current.getChildElement(current
0472:                                .getChildIndex() + 1);
0473:                        current.removed.add(leaf);
0474:                        current.removed.add(next);
0475:                        current.createLeafElement(leaf.getAttributes(), leaf
0476:                                .getStartOffset(), offset);
0477:                        current.createLeafElement(next.getAttributes(), offset,
0478:                                next.getEndOffset());
0479:                    }
0480:                }
0481:
0482:                private void insertStartTag(final ElementSpec spec) {
0483:                    switch (spec.getDirection()) {
0484:                    case ElementSpec.OriginateDirection:
0485:                        insertStartOriginate(spec);
0486:                        break;
0487:
0488:                    case ElementSpec.JoinNextDirection:
0489:                        insertStartJoinNext(spec);
0490:                        break;
0491:
0492:                    case ElementSpec.JoinPreviousDirection:
0493:                        insertStartJoinPrevious(spec);
0494:                        break;
0495:
0496:                    case ElementSpec.JoinFractureDirection:
0497:                        insertStartFracture(spec);
0498:                        break;
0499:
0500:                    default:
0501:                        throw new Error(Messages.getString(
0502:                                "swing.err.13", "ElementSpec")); //$NON-NLS-1$ //$NON-NLS-2$
0503:                    }
0504:                }
0505:
0506:                private void insertStartFracture(final ElementSpec spec) {
0507:                    final AttributeSet attrs = spec.getDirection() == ElementSpec.OriginateDirection ? spec
0508:                            .getAttributes()
0509:                            : findLastExistedBranch().getAttributes();
0510:                    final BranchElement newBranch = (BranchElement) createBranchElement(
0511:                            current.element, attrs);
0512:
0513:                    final ChangeDesc lastChange = (ChangeDesc) changes
0514:                            .get(changes.size() - 1);
0515:                    int startIndex = lastChange.getChildIndexAtOffset(offset);
0516:                    if (lastChange.getChildElement(startIndex).getEndOffset() <= offset) {
0517:                        ++startIndex;
0518:                    }
0519:                    moveChildren(newBranch, lastChange, startIndex);
0520:
0521:                    current.added.add(newBranch);
0522:                    if (current.getChildIndex() == -1) {
0523:                        int newIndex = current.getChildIndexAtOffset(offset);
0524:                        if (newBranch.getElementCount() > 0
0525:                                && newBranch.getEndOffset() > current
0526:                                        .getChildElement(newIndex)
0527:                                        .getStartOffset()) {
0528:                            ++newIndex;
0529:                        }
0530:                        current.setChildIndex(newIndex);
0531:                    }
0532:                    if (current.isApplied()) {
0533:                        int replaceIndex = current
0534:                                .getChildIndexAtOffset(offset);
0535:                        if (newBranch.getElementCount() > 0
0536:                                && newBranch.getEndOffset() > current
0537:                                        .getChildElement(replaceIndex)
0538:                                        .getStartOffset()) {
0539:                            ++replaceIndex;
0540:                        }
0541:                        current.element.replace(replaceIndex, 0,
0542:                                new Element[] { newBranch });
0543:                    } else {
0544:                        current.apply();
0545:                    }
0546:
0547:                    current = new ChangeDesc(newBranch, true);
0548:                    changeStack.push(current);
0549:                }
0550:
0551:                private void moveChildren(final BranchElement newParent,
0552:                        final ChangeDesc sourceDesc, final int startIndex) {
0553:                    // copy all elements from lastBranch to the new one
0554:                    final int count = sourceDesc.element.getElementCount();
0555:                    final Element[] children = new Element[count - startIndex];
0556:                    for (int i = startIndex; i < count; i++) {
0557:                        children[i - startIndex] = clone(newParent, sourceDesc
0558:                                .getChildElement(i));
0559:                    }
0560:                    // Now we need to remove all previously added elements which were
0561:                    // copied from added list
0562:                    final int i = startIndex - sourceDesc.getChildIndex();
0563:                    for (int j = startIndex; j < count; j++) {
0564:                        final Object addedElement = sourceDesc
0565:                                .getAddedElement(i);
0566:                        final Object existingElement = sourceDesc
0567:                                .getChildElement(j);
0568:                        if (addedElement == existingElement) {
0569:                            sourceDesc.added.remove(addedElement);
0570:                        } else if (!sourceDesc.justCreated) {
0571:                            sourceDesc.removed.add(existingElement);
0572:                        }
0573:                    }
0574:                    // Complete the removal of elements from source
0575:                    if (count - startIndex > 0) {
0576:                        sourceDesc.element.replace(startIndex, count
0577:                                - startIndex, new Element[0]);
0578:                    }
0579:
0580:                    // Place copied children into the new parent
0581:                    newParent.replace(0, 0, children);
0582:                }
0583:
0584:                private void insertStartOriginate(final ElementSpec spec) {
0585:                    if (current == null) {
0586:                        insertStartJoinPrevious(spec);
0587:                    } else if (!create && !changes.isEmpty()) {
0588:                        insertStartFracture(spec);
0589:                    } else {
0590:                        Element branch = createBranchElement(current.element,
0591:                                spec.getAttributes());
0592:                        current.setChildIndexByOffset(offset);
0593:                        current.added.add(branch);
0594:                        current = new ChangeDesc(branch, true);
0595:                        changeStack.push(current);
0596:                    }
0597:                }
0598:
0599:                private void insertStartJoinNext(final ElementSpec spec) {
0600:                    current = new ChangeDesc(current.getChildAtOffset(offset));
0601:                    changeStack.push(current);
0602:                }
0603:
0604:                private void insertStartJoinPrevious(final ElementSpec spec) {
0605:                    if (current == null) {
0606:                        current = new ChangeDesc(getRootElement());
0607:                        // TODO are old attributes to be removed?
0608:                        final AttributeSet specAttr = spec.getAttributes();
0609:                        if (specAttr != null) {
0610:                            ((AbstractElement) getRootElement())
0611:                                    .addAttributes(specAttr);
0612:                        }
0613:                        changeStack.push(current);
0614:                    } else {
0615:                        current = new ChangeDesc(current
0616:                                .getChildAtOffset(offset));
0617:                        changeStack.push(current);
0618:                    }
0619:                }
0620:
0621:                private void insertEndTag() {
0622:                    if (current.isEmpty()) {
0623:                        current.setChildIndexByOffset(offset);
0624:                        Element leaf = current.getCurrentChild();
0625:                        final int start = leaf.getStartOffset();
0626:                        final int end = leaf.getEndOffset();
0627:                        if (start < offset && offset < end
0628:                                || start < offset + length
0629:                                && offset + length < end) {
0630:
0631:                            if (leaf.isLeaf()) {
0632:                                current.splitLeafElement(leaf, offset, offset
0633:                                        + length, false, null);
0634:                            } else if (length != 0) {
0635:                                BranchElement rightBranch = splitBranch(leaf);
0636:                                current.added.add(rightBranch);
0637:                                int newIndex = current
0638:                                        .getChildIndexAtOffset(offset + length);
0639:                                if (rightBranch.getElementCount() > 0
0640:                                        && rightBranch.getEndOffset() > current
0641:                                                .getChildElement(newIndex)
0642:                                                .getStartOffset()) {
0643:                                    ++newIndex;
0644:                                }
0645:                                current.childIndex = newIndex;
0646:                            }
0647:                        }
0648:                    }
0649:                    leaveParagraph();
0650:                    changes.add(current);
0651:                    changeStack.pop();
0652:                    current = changeStack.empty() ? null
0653:                            : (ChangeDesc) changeStack.peek();
0654:                }
0655:
0656:                private BranchElement splitBranch(final Element branch) {
0657:                    BranchElement result = current.createBranchElement(branch
0658:                            .getAttributes());
0659:                    final ChangeDesc lastChange = (ChangeDesc) changes
0660:                            .get(changes.size() - 1);
0661:                    int startIndex = lastChange.getChildIndexAtOffset(offset
0662:                            + length);
0663:                    moveChildren(result, lastChange, startIndex);
0664:                    return result;
0665:                }
0666:
0667:                private BranchElement findLastExistedBranch() {
0668:                    int i = changes.size() - 1;
0669:                    ChangeDesc desc = null;
0670:                    while (i >= 0
0671:                            && (desc = (ChangeDesc) changes.get(i)).justCreated) {
0672:                        i--;
0673:                    }
0674:                    return i >= 0 ? desc.element : null;
0675:                }
0676:
0677:                private void leaveParagraph() {
0678:                    if (current == null || current.isEmpty()) {
0679:                        return;
0680:                    }
0681:
0682:                    if (tail != null) {
0683:                        current.added.add(tail);
0684:                    }
0685:                    tail = null;
0686:                    current.apply();
0687:                }
0688:
0689:                private Element[] listToElementArray(final List list) {
0690:                    return (Element[]) list.toArray(new Element[list.size()]);
0691:                }
0692:
0693:                private void initChangeLists() {
0694:                    changeStack = new Stack();
0695:                    changes = new ArrayList();
0696:                }
0697:
0698:                private void prepare(final int offset, final int length,
0699:                        final DefaultDocumentEvent event) {
0700:                    this .offset = offset;
0701:                    this .length = length;
0702:                    this .event = event;
0703:
0704:                    this .changes.clear();
0705:                    this .changeStack.clear();
0706:                    this .current = null;
0707:
0708:                    this .create = false;
0709:                    this .tail = null;
0710:                }
0711:
0712:                private void readObject(final ObjectInputStream ois)
0713:                        throws IOException, ClassNotFoundException {
0714:
0715:                    ois.defaultReadObject();
0716:                    initChangeLists();
0717:                }
0718:
0719:                private void writeObject(final ObjectOutputStream oos)
0720:                        throws IOException {
0721:
0722:                    oos.defaultWriteObject();
0723:                }
0724:            }
0725:
0726:            public static class ElementSpec {
0727:                public static final short ContentType = 3;
0728:                public static final short EndTagType = 2;
0729:                public static final short StartTagType = 1;
0730:
0731:                public static final short JoinFractureDirection = 7;
0732:                public static final short JoinNextDirection = 5;
0733:                public static final short JoinPreviousDirection = 4;
0734:                public static final short OriginateDirection = 6;
0735:
0736:                private AttributeSet attrs;
0737:                private short type;
0738:                private char[] text;
0739:                private int offset;
0740:                private int length;
0741:                private short direction;
0742:
0743:                public ElementSpec(final AttributeSet attrs, final short type) {
0744:                    this (attrs, type, null, 0, 0);
0745:                }
0746:
0747:                public ElementSpec(final AttributeSet attrs, final short type,
0748:                        final char[] text, final int offset, final int length) {
0749:                    this .attrs = attrs;
0750:                    this .type = type;
0751:                    this .text = text;
0752:                    this .offset = offset;
0753:                    this .length = length;
0754:
0755:                    this .direction = OriginateDirection;
0756:                }
0757:
0758:                public ElementSpec(final AttributeSet attrs, final short type,
0759:                        final int length) {
0760:                    this (attrs, type, null, 0, length);
0761:                }
0762:
0763:                public char[] getArray() {
0764:                    return text;
0765:                }
0766:
0767:                public AttributeSet getAttributes() {
0768:                    return attrs;
0769:                }
0770:
0771:                public short getDirection() {
0772:                    return direction;
0773:                }
0774:
0775:                public int getLength() {
0776:                    return length;
0777:                }
0778:
0779:                public int getOffset() {
0780:                    return offset;
0781:                }
0782:
0783:                public short getType() {
0784:                    return type;
0785:                }
0786:
0787:                public void setDirection(final short direction) {
0788:                    this .direction = direction;
0789:                }
0790:
0791:                public void setType(final short type) {
0792:                    this .type = type;
0793:                }
0794:
0795:                /*
0796:                 * The format of the string is based on 1.5 release behavior
0797:                 * which can be revealed using the following code:
0798:                 *
0799:                 *     Object obj = new DefaultStyledDocument.ElementSpec(null,
0800:                 *         DefaultStyledDocument.ElementSpec.ContentType);
0801:                 *     System.out.println(obj.toString());
0802:                 */
0803:                public String toString() {
0804:                    String result;
0805:                    switch (type) {
0806:                    case StartTagType:
0807:                        result = "StartTag:";
0808:                        break;
0809:                    case ContentType:
0810:                        result = "Content:";
0811:                        break;
0812:                    case EndTagType:
0813:                        result = "EndTag:";
0814:                        break;
0815:                    default:
0816:                        result = "??:";
0817:                    }
0818:
0819:                    switch (direction) {
0820:                    case OriginateDirection:
0821:                        result += "Originate:";
0822:                        break;
0823:                    case JoinFractureDirection:
0824:                        result += "Fracture:";
0825:                        break;
0826:                    case JoinNextDirection:
0827:                        result += "JoinNext:";
0828:                        break;
0829:                    case JoinPreviousDirection:
0830:                        result += "JoinPrevious:";
0831:                        break;
0832:                    default:
0833:                        result += "??:";
0834:                    }
0835:
0836:                    result += length;
0837:
0838:                    return result;
0839:                }
0840:
0841:            }
0842:
0843:            protected class SectionElement extends BranchElement {
0844:                public SectionElement() {
0845:                    super (null, null);
0846:                }
0847:
0848:                public String getName() {
0849:                    return AbstractDocument.SectionElementName;
0850:                }
0851:            }
0852:
0853:            private final class ChangeDesc {
0854:                public final BranchElement element;
0855:                private int childIndex = -1;
0856:                public final List added = new ArrayList();
0857:                public final List removed = new ArrayList();
0858:                public final boolean justCreated;
0859:                private boolean applied;
0860:
0861:                public ChangeDesc(final Element element) {
0862:                    this (element, false);
0863:                }
0864:
0865:                public ChangeDesc(final Element element,
0866:                        final boolean justCreated) {
0867:                    this .element = (BranchElement) element;
0868:                    this .justCreated = justCreated;
0869:                }
0870:
0871:                public ChangeDesc(final Element element, final int offset) {
0872:                    this (element, false);
0873:                    setChildIndexByOffset(offset);
0874:                }
0875:
0876:                public void setChildIndex(final int index) {
0877:                    if (this .childIndex == -1) {
0878:                        this .childIndex = index;
0879:                    }
0880:                }
0881:
0882:                public int getChildIndex() {
0883:                    return childIndex;
0884:                }
0885:
0886:                public Element[] getChildrenAdded() {
0887:                    return (Element[]) added.toArray(new Element[added.size()]);
0888:                }
0889:
0890:                public Element[] getChildrenRemoved() {
0891:                    return (Element[]) removed.toArray(new Element[removed
0892:                            .size()]);
0893:                }
0894:
0895:                public ElementEdit toElementEdit() {
0896:                    return new ElementEdit(element, childIndex,
0897:                            getChildrenRemoved(), getChildrenAdded());
0898:                }
0899:
0900:                public void apply() {
0901:                    if (applied || isEmpty()) {
0902:                        return;
0903:                    }
0904:                    if (childIndex == -1) {
0905:                        childIndex = 0;
0906:                    }
0907:
0908:                    applied = true;
0909:                    element.replace(childIndex, removed.size(),
0910:                            getChildrenAdded());
0911:                }
0912:
0913:                public boolean isEmpty() {
0914:                    return removed.size() == 0 && added.size() == 0;
0915:                }
0916:
0917:                public boolean isApplied() {
0918:                    return applied;
0919:                }
0920:
0921:                public void createLeafElement(final AttributeSet attr,
0922:                        final int start, final int end) {
0923:                    added.add(DefaultStyledDocument.this .createLeafElement(
0924:                            element, attr, start, end));
0925:                }
0926:
0927:                public BranchElement createBranchElement(final AttributeSet attr) {
0928:                    return (BranchElement) DefaultStyledDocument.this 
0929:                            .createBranchElement(element, attr);
0930:                }
0931:
0932:                public void splitLeafElement(final Element leaf,
0933:                        final int splitOffset) {
0934:                    final AttributeSet attrs = leaf.getAttributes();
0935:                    createLeafElement(attrs, leaf.getStartOffset(), splitOffset);
0936:                    createLeafElement(attrs, splitOffset, leaf.getEndOffset());
0937:                    removed.add(leaf);
0938:                }
0939:
0940:                public void splitLeafElement(final Element child,
0941:                        final int splitOffset1, final int splitOffset2,
0942:                        final boolean createMiddle,
0943:                        final AttributeSet middleAttr) {
0944:                    splitLeafElement(child, splitOffset1, splitOffset2,
0945:                            splitOffset2, createMiddle, middleAttr);
0946:                }
0947:
0948:                public void splitLeafElement(final Element child,
0949:                        final int splitOffset1, final int splitOffset2,
0950:                        final int splitOffset3, final boolean createMiddle,
0951:                        final AttributeSet middleAttr) {
0952:                    final AttributeSet attrs = child.getAttributes();
0953:                    if (child.getStartOffset() < splitOffset1) {
0954:                        createLeafElement(attrs, child.getStartOffset(),
0955:                                splitOffset1);
0956:                    }
0957:                    if (createMiddle) {
0958:                        createLeafElement(middleAttr, splitOffset1,
0959:                                splitOffset2);
0960:                    }
0961:                    if (splitOffset3 < child.getEndOffset()) {
0962:                        createLeafElement(attrs, splitOffset3, child
0963:                                .getEndOffset());
0964:                    }
0965:                    removed.add(child);
0966:                }
0967:
0968:                public void setChildIndexByOffset(final int offset) {
0969:                    setChildIndex(element.getElementIndex(offset));
0970:                }
0971:
0972:                public Element getChildAtOffset(final int offset) {
0973:                    return element.getElement(element.getElementIndex(offset));
0974:                }
0975:
0976:                public int getChildIndexAtOffset(final int offset) {
0977:                    return element.getElementIndex(offset);
0978:                }
0979:
0980:                public Element getCurrentChild() {
0981:                    return element.getElement(childIndex);
0982:                }
0983:
0984:                public Element getChildElement(final int index) {
0985:                    return element.getElement(index);
0986:                }
0987:
0988:                public void removeChildElement(final int index) {
0989:                    removed.add(element.getElement(index));
0990:                }
0991:
0992:                public Element getAddedElement(final int i) {
0993:                    return (i > 0 && i < added.size()) ? (Element) added.get(i)
0994:                            : null;
0995:                }
0996:
0997:                public Element getLastAddedElement() {
0998:                    return (Element) added.get(added.size() - 1);
0999:                }
1000:
1001:                public Element getLastRemovedElement() {
1002:                    return (Element) removed.get(removed.size() - 1);
1003:                }
1004:            }
1005:
1006:            public static final int BUFFER_SIZE_DEFAULT = 4096;
1007:            private transient AttributeSet defaultLogicalStyle;
1008:
1009:            protected ElementBuffer buffer;
1010:
1011:            private ChangeListener styleContextChangeListener;
1012:            private ChangeListener styleChangeListener;
1013:
1014:            public DefaultStyledDocument() {
1015:                this (new GapContent(BUFFER_SIZE_DEFAULT), new StyleContext());
1016:            }
1017:
1018:            public DefaultStyledDocument(final Content content,
1019:                    final StyleContext styles) {
1020:                super (content, styles);
1021:                createDefaultLogicalStyle();
1022:                buffer = new ElementBuffer(createDefaultRoot());
1023:            }
1024:
1025:            public DefaultStyledDocument(final StyleContext styles) {
1026:                this (new GapContent(BUFFER_SIZE_DEFAULT), styles);
1027:            }
1028:
1029:            public Style addStyle(final String name, final Style parent) {
1030:                return getStyleContext().addStyle(name, parent);
1031:            }
1032:
1033:            public void removeStyle(final String name) {
1034:                getStyleContext().removeStyle(name);
1035:            }
1036:
1037:            public Style getStyle(final String name) {
1038:                return getStyleContext().getStyle(name);
1039:            }
1040:
1041:            public Enumeration<?> getStyleNames() {
1042:                return getStyleContext().getStyleNames();
1043:            }
1044:
1045:            public Color getForeground(final AttributeSet attrs) {
1046:                return getStyleContext().getForeground(attrs);
1047:            }
1048:
1049:            public Color getBackground(final AttributeSet attrs) {
1050:                return getStyleContext().getBackground(attrs);
1051:            }
1052:
1053:            public Font getFont(final AttributeSet attrs) {
1054:                return getStyleContext().getFont(attrs);
1055:            }
1056:
1057:            public Element getDefaultRootElement() {
1058:                return buffer.getRootElement();
1059:            }
1060:
1061:            public Element getCharacterElement(final int offset) {
1062:                final Element paragraph = getParagraphElement(offset);
1063:                return paragraph.getElement(paragraph.getElementIndex(offset));
1064:            }
1065:
1066:            public Element getParagraphElement(final int offset) {
1067:                Element branch;
1068:                Element child = getDefaultRootElement();
1069:                do {
1070:                    branch = child;
1071:                    child = branch.getElement(branch.getElementIndex(offset));
1072:                } while (!child.isLeaf());
1073:                return branch;
1074:            }
1075:
1076:            public void setCharacterAttributes(final int offset,
1077:                    final int length, final AttributeSet attrs,
1078:                    final boolean replace) {
1079:                if (checkInvalid(offset, length)) {
1080:                    return;
1081:                }
1082:
1083:                writeLock();
1084:                try {
1085:                    final DefaultDocumentEvent event = new DefaultDocumentEvent(
1086:                            offset, length, EventType.CHANGE);
1087:
1088:                    buffer.change(offset, length, event);
1089:
1090:                    AbstractElement element;
1091:                    int currentOffset = offset;
1092:                    final int limit = offset + length;
1093:                    while (currentOffset < limit) {
1094:                        element = (AbstractElement) getCharacterElement(currentOffset);
1095:                        event.addEdit(new AttributeUndoableEdit(element, attrs,
1096:                                replace));
1097:                        if (replace) {
1098:                            element.removeAttributes(element
1099:                                    .getAttributeNames());
1100:                        }
1101:                        element.addAttributes(attrs);
1102:                        currentOffset = element.getEndOffset();
1103:                    }
1104:
1105:                    event.end();
1106:                    fireChangedUpdate(event);
1107:                    fireUndoableEditUpdate(new UndoableEditEvent(this , event));
1108:                } finally {
1109:                    writeUnlock();
1110:                }
1111:            }
1112:
1113:            public void setParagraphAttributes(final int offset,
1114:                    final int length, final AttributeSet attrs,
1115:                    final boolean replace) {
1116:                if (checkInvalid(offset, length)) {
1117:                    return;
1118:                }
1119:
1120:                writeLock();
1121:                try {
1122:                    final DefaultDocumentEvent event = new DefaultDocumentEvent(
1123:                            offset, length, EventType.CHANGE);
1124:
1125:                    AbstractElement element;
1126:                    int currentOffset = offset;
1127:                    final int limit = offset + length;
1128:                    while (currentOffset < limit) {
1129:                        element = (AbstractElement) getParagraphElement(currentOffset);
1130:                        event.addEdit(new AttributeUndoableEdit(element, attrs,
1131:                                replace));
1132:                        if (replace) {
1133:                            element.removeAttributes(element
1134:                                    .getAttributeNames());
1135:                        }
1136:                        element.addAttributes(attrs);
1137:                        currentOffset = element.getEndOffset();
1138:                    }
1139:
1140:                    event.end();
1141:                    fireChangedUpdate(event);
1142:                    fireUndoableEditUpdate(new UndoableEditEvent(this , event));
1143:                } finally {
1144:                    writeUnlock();
1145:                }
1146:            }
1147:
1148:            public void setLogicalStyle(final int offset, final Style style) {
1149:                final AbstractElement branch = (AbstractElement) getParagraphElement(offset);
1150:                writeLock();
1151:                try {
1152:                    branch.setResolveParent(style);
1153:                } finally {
1154:                    writeUnlock();
1155:                }
1156:            }
1157:
1158:            public Style getLogicalStyle(final int offset) {
1159:                final Element element = getParagraphElement(offset);
1160:                Object resolver = element.getAttributes().getResolveParent();
1161:                return resolver instanceof  Style ? (Style) resolver : null;
1162:            }
1163:
1164:            public void addDocumentListener(final DocumentListener listener) {
1165:                super .addDocumentListener(listener);
1166:                getStyleContext().addChangeListener(getStyleContextListener());
1167:                addListenerToStyles();
1168:            }
1169:
1170:            public void removeDocumentListener(final DocumentListener listener) {
1171:                super .removeDocumentListener(listener);
1172:                if (getDocumentListeners().length == 0) {
1173:                    getStyleContext().removeChangeListener(
1174:                            getStyleContextListener());
1175:                    removeListenerFromStyles();
1176:                }
1177:            }
1178:
1179:            protected AbstractElement createDefaultRoot() {
1180:                final BranchElement result = new SectionElement();
1181:                writeLock();
1182:                try {
1183:                    final BranchElement paragraph = (BranchElement) createBranchElement(
1184:                            result, null);
1185:                    paragraph
1186:                            .setResolveParent(getStyle(StyleContext.DEFAULT_STYLE));
1187:                    final Element content = createLeafElement(paragraph, null,
1188:                            getStartPosition().getOffset(), getEndPosition()
1189:                                    .getOffset());
1190:                    paragraph.replace(0, 0, new Element[] { content });
1191:                    result.replace(0, 0, new Element[] { paragraph });
1192:                } finally {
1193:                    writeUnlock();
1194:                }
1195:                return result;
1196:            }
1197:
1198:            protected void create(final ElementSpec[] specs) {
1199:                final StringBuffer text = appendSpecsText(specs);
1200:
1201:                writeLock();
1202:                try {
1203:                    if (getLength() > 0) {
1204:                        try {
1205:                            remove(0, getLength());
1206:                        } catch (BadLocationException e) {
1207:                            e.printStackTrace();
1208:                        }
1209:                    }
1210:
1211:                    final int offset = 0;
1212:                    UndoableEdit contentInsert = null;
1213:                    try {
1214:                        contentInsert = getContent().insertString(offset,
1215:                                text.toString());
1216:                    } catch (BadLocationException e) {
1217:                        e.printStackTrace();
1218:                    }
1219:
1220:                    DefaultDocumentEvent event = new DefaultDocumentEvent(
1221:                            offset, text.length(), EventType.INSERT);
1222:                    if (contentInsert != null) {
1223:                        event.addEdit(contentInsert);
1224:                    }
1225:                    event.addEdit(new AttributeUndoableEdit(buffer
1226:                            .getRootElement(), getStyleContext().getEmptySet(),
1227:                            true));
1228:                    ((AbstractElement) buffer.getRootElement())
1229:                            .removeAttributes(buffer.getRootElement()
1230:                                    .getAttributes());
1231:
1232:                    buffer.create(specs, event);
1233:
1234:                    event.end();
1235:                    fireInsertUpdate(event);
1236:                    if (contentInsert != null) {
1237:                        fireUndoableEditUpdate(new UndoableEditEvent(this ,
1238:                                event));
1239:                    }
1240:                } finally {
1241:                    writeUnlock();
1242:                }
1243:            }
1244:
1245:            protected void insert(final int offset, final ElementSpec[] specs)
1246:                    throws BadLocationException {
1247:
1248:                final StringBuffer text = appendSpecsText(specs);
1249:                writeLock();
1250:                try {
1251:                    UndoableEdit contentInsert = getContent().insertString(
1252:                            offset, text.toString());
1253:
1254:                    DefaultDocumentEvent event = new DefaultDocumentEvent(
1255:                            offset, text.length(), EventType.INSERT);
1256:                    if (contentInsert != null) {
1257:                        event.addEdit(contentInsert);
1258:                    }
1259:
1260:                    buffer.insert(offset, text.length(), specs, event);
1261:
1262:                    event.end();
1263:                    fireInsertUpdate(event);
1264:                    if (contentInsert != null) {
1265:                        fireUndoableEditUpdate(new UndoableEditEvent(this ,
1266:                                event));
1267:                    }
1268:                } finally {
1269:                    writeUnlock();
1270:                }
1271:            }
1272:
1273:            protected void insertUpdate(final DefaultDocumentEvent event,
1274:                    final AttributeSet attrs) {
1275:                final AttributeSet attributes = attrs == null ? getStyleContext()
1276:                        .getEmptySet()
1277:                        : attrs;
1278:
1279:                final List specs = new LinkedList();
1280:
1281:                String text = null;
1282:                final int offset = event.getOffset();
1283:                final int length = event.getLength();
1284:
1285:                try {
1286:                    text = getText(offset, length);
1287:                } catch (final BadLocationException e) {
1288:                }
1289:
1290:                boolean splitPrevParagraph = false;
1291:                try {
1292:                    splitPrevParagraph = offset > 0
1293:                            && getText(offset - 1, 1).charAt(0) == '\n';
1294:                } catch (final BadLocationException e) {
1295:                }
1296:
1297:                final int firstBreak = text.indexOf('\n');
1298:                final int lastBreak = text.lastIndexOf('\n');
1299:                final boolean hasLineBreak = firstBreak != -1;
1300:
1301:                Element charElem = getCharacterElement(offset);
1302:                ElementSpec spec = null;
1303:                if (!hasLineBreak) {
1304:                    if (splitPrevParagraph) {
1305:                        splitBranch(specs, offset, length, charElem,
1306:                                ElementSpec.JoinNextDirection);
1307:                        // The direction of the next Content element must be chosen
1308:                        // based on attributes of the first Content element
1309:                        // in the next paragraph
1310:                        charElem = getCharacterElement(offset + length);
1311:                    }
1312:                    spec = new ElementSpec(attributes, ElementSpec.ContentType,
1313:                            length);
1314:                    if (charElem.getAttributes().isEqual(attributes)) {
1315:                        spec
1316:                                .setDirection(splitPrevParagraph ? ElementSpec.JoinNextDirection
1317:                                        : ElementSpec.JoinPreviousDirection);
1318:                    }
1319:                    specs.add(spec);
1320:                } else {
1321:                    int currentOffset = offset;
1322:                    int currentIndex = firstBreak;
1323:                    int processedLength = 0;
1324:
1325:                    if (splitPrevParagraph) {
1326:                        splitBranch(specs, offset, length, charElem,
1327:                                ElementSpec.OriginateDirection);
1328:                    }
1329:
1330:                    while (currentOffset < offset + length) {
1331:                        if (!(currentIndex < 0)) {
1332:                            spec = new ElementSpec(attributes,
1333:                                    ElementSpec.ContentType, currentIndex + 1
1334:                                            - processedLength);
1335:                            currentOffset += spec.getLength();
1336:                            processedLength += spec.getLength();
1337:                            if (specs.size() == 0
1338:                                    && charElem.getAttributes().isEqual(
1339:                                            attributes)) {
1340:
1341:                                spec
1342:                                        .setDirection(ElementSpec.JoinPreviousDirection);
1343:                            }
1344:                            specs.add(spec);
1345:
1346:                            specs.add(new ElementSpec(null,
1347:                                    ElementSpec.EndTagType));
1348:
1349:                            spec = new ElementSpec(defaultLogicalStyle,
1350:                                    ElementSpec.StartTagType);
1351:                            if (currentIndex == lastBreak) {
1352:                                spec
1353:                                        .setDirection(splitPrevParagraph ? ElementSpec.JoinNextDirection
1354:                                                : ElementSpec.JoinFractureDirection);
1355:                            }
1356:                            specs.add(spec);
1357:
1358:                            currentIndex = text.indexOf('\n', currentIndex + 1);
1359:                        } else {
1360:                            spec = new ElementSpec(attributes,
1361:                                    ElementSpec.ContentType, length
1362:                                            - processedLength);
1363:                            currentOffset += spec.getLength();
1364:                            processedLength += spec.getLength();
1365:                            if (getCharacterElement(currentOffset)
1366:                                    .getAttributes().isEqual(attributes)) {
1367:
1368:                                spec
1369:                                        .setDirection(ElementSpec.JoinNextDirection);
1370:                            }
1371:                            specs.add(spec);
1372:                        }
1373:                    }
1374:
1375:                }
1376:
1377:                final Object[] specArray = specs.toArray(new ElementSpec[specs
1378:                        .size()]);
1379:                buffer.insert(offset, length, (ElementSpec[]) specArray, event);
1380:
1381:                super .insertUpdate(event, attrs);
1382:            }
1383:
1384:            private void splitBranch(final List specs, final int offset,
1385:                    final int length, final Element leaf,
1386:                    final short lastSpecDirection) {
1387:                ElementSpec spec = null;
1388:                Element branch = leaf.getParentElement();
1389:                final int endOffset = offset + length;
1390:                while (branch != null && branch.getEndOffset() == endOffset) {
1391:                    specs.add(new ElementSpec(null, ElementSpec.EndTagType));
1392:                    branch = branch.getParentElement();
1393:                }
1394:
1395:                branch = branch.getElement(branch.getElementIndex(offset) + 1);
1396:                while (branch != null && !branch.isLeaf()
1397:                        && branch.getStartOffset() == endOffset) {
1398:                    spec = new ElementSpec(branch.getAttributes(),
1399:                            ElementSpec.StartTagType);
1400:                    spec.setDirection(ElementSpec.JoinNextDirection);
1401:                    specs.add(spec);
1402:                    branch = branch.getElement(0);
1403:                }
1404:                spec.setDirection(lastSpecDirection);
1405:            }
1406:
1407:            protected void removeUpdate(final DefaultDocumentEvent event) {
1408:                buffer.remove(event.getOffset(), event.getLength(), event);
1409:            }
1410:
1411:            protected void styleChanged(final Style style) {
1412:            }
1413:
1414:            private StringBuffer appendSpecsText(final ElementSpec[] specs) {
1415:                final StringBuffer result = new StringBuffer();
1416:                for (int i = 0; i < specs.length; i++) {
1417:                    if (specs[i].getLength() > 0) {
1418:                        result.append(specs[i].getArray(),
1419:                                specs[i].getOffset(), specs[i].getLength());
1420:                    }
1421:                }
1422:                return result;
1423:            }
1424:
1425:            private void addListenerToStyles() {
1426:                final Enumeration names = getStyleNames();
1427:                while (names.hasMoreElements()) {
1428:                    String name = (String) names.nextElement();
1429:                    getStyle(name).addChangeListener(getStyleChangeListener());
1430:                }
1431:            }
1432:
1433:            private void removeListenerFromStyles() {
1434:                final Enumeration names = getStyleNames();
1435:                while (names.hasMoreElements()) {
1436:                    String name = (String) names.nextElement();
1437:                    getStyle(name).removeChangeListener(
1438:                            getStyleChangeListener());
1439:                }
1440:            }
1441:
1442:            private boolean checkInvalid(final int offset, final int length) {
1443:                return offset < 0 || length <= 0
1444:                        || offset + length > getLength() + 1;
1445:            }
1446:
1447:            private void createDefaultLogicalStyle() {
1448:                final StyleContext styles = getStyleContext();
1449:                defaultLogicalStyle = styles.addAttribute(styles.getEmptySet(),
1450:                        AttributeSet.ResolveAttribute, styles
1451:                                .getStyle(StyleContext.DEFAULT_STYLE));
1452:            }
1453:
1454:            private ChangeListener getStyleChangeListener() {
1455:                if (styleChangeListener == null) {
1456:                    styleChangeListener = new ChangeListener() {
1457:                        public void stateChanged(final ChangeEvent e) {
1458:                            styleChanged((Style) e.getSource());
1459:                        }
1460:                    };
1461:                }
1462:                return styleChangeListener;
1463:            }
1464:
1465:            private ChangeListener getStyleContextListener() {
1466:                if (styleContextChangeListener == null) {
1467:                    styleContextChangeListener = new ChangeListener() {
1468:                        public void stateChanged(final ChangeEvent e) {
1469:                            removeListenerFromStyles();
1470:                            addListenerToStyles();
1471:                        }
1472:                    };
1473:                }
1474:                return styleContextChangeListener;
1475:            }
1476:
1477:            private StyleContext getStyleContext() {
1478:                return (StyleContext) getAttributeContext();
1479:            }
1480:
1481:            private void readObject(final ObjectInputStream ois)
1482:                    throws IOException, ClassNotFoundException {
1483:
1484:                ois.defaultReadObject();
1485:                createDefaultLogicalStyle();
1486:            }
1487:
1488:            private void writeObject(final ObjectOutputStream oos)
1489:                    throws IOException {
1490:
1491:                oos.defaultWriteObject();
1492:            }
1493:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.