001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Alexey A. Ivanov
019: * @version $Revision$
020: */package javax.swing.text;
021:
022: import java.util.List;
023: import javax.swing.event.DocumentEvent.ElementChange;
024: import javax.swing.event.DocumentEvent.EventType;
025: import javax.swing.text.AbstractDocument.BranchElement;
026: import javax.swing.text.AbstractDocument.Content;
027: import javax.swing.text.AbstractDocument.DefaultDocumentEvent;
028: import javax.swing.text.DefaultStyledDocument.ElementBuffer;
029: import junit.framework.TestCase;
030:
031: /**
032: * Tests the behavior of
033: * <code>DefaultStyledDocument.ElementBuffer.change()</code> method.
034: *
035: */
036: public class DefaultStyledDocument_ElementBuffer_ChangeTest extends
037: TestCase {
038: private DefaultStyledDocument doc;
039:
040: private Element root;
041:
042: private ElementBuffer buf;
043:
044: private DefaultDocumentEvent event;
045:
046: private Content content;
047:
048: private Element paragraph;
049:
050: private static final AttributeSet bold = DefStyledDoc_Helpers.bold;
051:
052: private static final AttributeSet italic = DefStyledDoc_Helpers.italic;
053:
054: @Override
055: protected void setUp() throws Exception {
056: super .setUp();
057: doc = new DefaultStyledDocument();
058: root = doc.getDefaultRootElement();
059: buf = new DefStyledDoc_Helpers.ElementBufferWithLogging(doc,
060: root);
061: doc.buffer = buf;
062: paragraph = root.getElement(0);
063: content = doc.getContent();
064: content.insertString(0, "plainbolditalic\ntext");
065: // Create the structure equivalent to this sequence:
066: //doc.insertString(doc.getLength(), "plain", null); // 5 chars
067: //doc.insertString(doc.getLength(), "bold", bold); // 4 chars
068: //doc.insertString(doc.getLength(), "italic", italic); // 6 chars
069: //doc.insertString(doc.getLength(), "\ntext", null); // 5 chars
070: doc.writeLock(); // Write lock needed to modify document structure
071: Element[] leaves = new Element[4];
072: leaves[0] = doc.createLeafElement(paragraph, null, 0, 5);
073: leaves[1] = doc.createLeafElement(paragraph, bold, 5, 9);
074: leaves[2] = doc.createLeafElement(paragraph, italic, 9, 15);
075: leaves[3] = doc.createLeafElement(paragraph, null, 15, 16);
076: ((BranchElement) paragraph).replace(0, 1, leaves);
077: BranchElement branch = (BranchElement) doc.createBranchElement(
078: root, null);
079: leaves = new Element[1];
080: leaves[0] = doc.createLeafElement(branch, null, 16, 21);
081: branch.replace(0, 0, leaves);
082: ((BranchElement) root).replace(1, 0, new Element[] { branch });
083: }
084:
085: @Override
086: protected void tearDown() throws Exception {
087: super .tearDown();
088: doc.writeUnlock();
089: }
090:
091: /**
092: * The change is applied to the whole element.
093: * No structure are expected to change.
094: */
095: public void testChangeFullElement() throws Exception {
096: Element boldElement = paragraph.getElement(1);
097: int offset = boldElement.getStartOffset();
098: int length = boldElement.getEndOffset() - offset;
099: buf.change(offset, length, createEvent(offset, length));
100: assertEquals(0, getEdits(event).size());
101: assertChildren(paragraph,
102: new int[] { 0, 5, 5, 9, 9, 15, 15, 16 },
103: new AttributeSet[] { null, bold, italic, null });
104: }
105:
106: /**
107: * The change is applied from the start of an element to its middle.
108: * The element is to be split.
109: */
110: public void testChangeElementStart() throws Exception {
111: Element boldElement = paragraph.getElement(1);
112: int offset = boldElement.getStartOffset();
113: int length = (boldElement.getEndOffset() - offset) / 2;
114: buf.change(offset, length, createEvent(offset, length));
115: final List<?> edits = getEdits(event);
116: assertEquals(1, edits.size());
117: assertChange(edits.get(0), paragraph, 1, new int[] { 5, 9 },
118: new int[] { 5, 7, 7, 9 });
119: assertChildren(paragraph, new int[] { 0, 5, 5, 7, 7, 9, 9, 15,
120: 15, 16 }, new AttributeSet[] { null, bold, bold,
121: italic, null });
122: }
123:
124: /**
125: * The change is applied from the middle of an element to its end.
126: * The element is to be split.
127: */
128: public void testChangeElementEnd() throws Exception {
129: Element boldElement = paragraph.getElement(1);
130: int offset = (boldElement.getStartOffset() + boldElement
131: .getEndOffset()) / 2;
132: int length = boldElement.getEndOffset() - offset;
133: buf.change(offset, length, createEvent(offset, length));
134: final List<?> edits = getEdits(event);
135: assertEquals(1, edits.size());
136: assertChange(edits.get(0), paragraph, 1, new int[] { 5, 9 },
137: new int[] { 5, 7, 7, 9 });
138: assertChildren(paragraph, new int[] { 0, 5, 5, 7, 7, 9, 9, 15,
139: 15, 16 }, new AttributeSet[] { null, bold, bold,
140: italic, null });
141: }
142:
143: /**
144: * The change is applied to two entire elements.
145: * No structure are expected to change.
146: */
147: public void testChangeFull2Elements() throws Exception {
148: Element plainElement = paragraph.getElement(0);
149: Element boldElement = paragraph.getElement(1);
150: int offset = plainElement.getStartOffset();
151: int length = boldElement.getEndOffset() - offset;
152: buf.change(offset, length, createEvent(offset, length));
153: assertEquals(0, getEdits(event).size());
154: assertChildren(paragraph,
155: new int[] { 0, 5, 5, 9, 9, 15, 15, 16 },
156: new AttributeSet[] { null, bold, italic, null });
157: }
158:
159: /**
160: * The change is applied from the start of an element to the middle of
161: * the next element.
162: * The former element is to be split, the other is unchanged.
163: */
164: public void testChange2ElementsStart() throws Exception {
165: Element plainElement = paragraph.getElement(0);
166: Element boldElement = paragraph.getElement(1);
167: int offset = plainElement.getStartOffset();
168: int length = (boldElement.getStartOffset() + boldElement
169: .getEndOffset()) / 2;
170: buf.change(offset, length, createEvent(offset, length));
171: final List<?> edits = getEdits(event);
172: assertEquals(1, edits.size());
173: assertChange(edits.get(0), paragraph, 1, new int[] { 5, 9 },
174: new int[] { 5, 7, 7, 9 });
175: assertChildren(paragraph, new int[] { 0, 5, 5, 7, 7, 9, 9, 15,
176: 15, 16 }, new AttributeSet[] { null, bold, bold,
177: italic, null });
178: }
179:
180: /**
181: * The change is applied from the middle of an element to the end of
182: * the next element.
183: * The first element is to be split, the other is unchanged.
184: */
185: public void testChange2ElementsEnd() throws Exception {
186: Element plainElement = paragraph.getElement(0);
187: Element boldElement = paragraph.getElement(1);
188: int offset = (plainElement.getStartOffset() + plainElement
189: .getEndOffset()) / 2;
190: int length = boldElement.getEndOffset() - offset;
191: buf.change(offset, length, createEvent(offset, length));
192: final List<?> edits = getEdits(event);
193: assertEquals(1, edits.size());
194: assertChange(edits.get(0), paragraph, 0, new int[] { 0, 5 },
195: new int[] { 0, 2, 2, 5 });
196: assertChildren(paragraph, new int[] { 0, 2, 2, 5, 5, 9, 9, 15,
197: 15, 16 }, new AttributeSet[] { null, null, bold,
198: italic, null });
199: }
200:
201: /**
202: * The change is applied so that it affects three elements:
203: * from the middle of the first element to the middle of the third one.
204: * It is expected that the first and third element will be split.
205: *
206: * Although the second element is left unchanged, it is added to the
207: * removed and added lists simultaneously. This way the merge of two
208: * edits is performed.
209: */
210: public void testChange3ElementsStartEnd() throws Exception {
211: Element plainElement = paragraph.getElement(0);
212: Element italicElement = paragraph.getElement(2);
213: int offset = (plainElement.getStartOffset() + plainElement
214: .getEndOffset()) / 2;
215: int length = (italicElement.getStartOffset() + italicElement
216: .getEndOffset())
217: / 2 - offset;
218: buf.change(offset, length, createEvent(offset, length));
219: final List<?> edits = getEdits(event);
220: assertEquals(1, edits.size());
221: assertChange(edits.get(0), paragraph, 0, new int[] { 0, 5, 5,
222: 9, 9, 15 },
223: new int[] { 0, 2, 2, 5, 5, 9, 9, 12, 12, 15 });
224: // Merge of two changes is performed by copying elements which
225: // lie between split ones
226: ElementChange change = (ElementChange) edits.get(0);
227: assertSame(change.getChildrenRemoved()[1], // bold [5, 9]
228: change.getChildrenAdded()[2]);
229: assertChildren(paragraph, new int[] { 0, 2, 2, 5, 5, 9, 9, 12,
230: 12, 15, 15, 16 }, new AttributeSet[] { null, null,
231: bold, italic, italic, null });
232: }
233:
234: /**
235: * The changes makes elements in two different paragraphs be split.
236: */
237: public void testChange2Paragraphs() throws Exception {
238: Element italicElement = paragraph.getElement(2);
239: Element paragraph2 = root.getElement(1);
240: int offset = (italicElement.getStartOffset() + italicElement
241: .getEndOffset()) / 2;
242: int length = (paragraph2.getStartOffset() + paragraph2
243: .getEndOffset())
244: / 2 - offset;
245: buf.change(offset, length, createEvent(offset, length));
246: final List<?> edits = getEdits(event);
247: assertEquals(2, edits.size());
248: assertChange(edits.get(0), paragraph, 2, new int[] { 9, 15 },
249: new int[] { 9, 12, 12, 15 });
250: assertChange(edits.get(1), paragraph2, 0, new int[] { 16, 21 },
251: new int[] { 16, 18, 18, 21 });
252: assertChildren(paragraph, new int[] { 0, 5, 5, 9, 9, 12, 12,
253: 15, 15, 16 }, new AttributeSet[] { null, bold, italic,
254: italic, null });
255: assertChildren(paragraph2, new int[] { 16, 18, 18, 21 },
256: new AttributeSet[] { null, null });
257: }
258:
259: private static void assertChange(final Object change,
260: final Element element, final int index,
261: final int[] removed, final int[] added) {
262: DefStyledDoc_Helpers.assertChange(change, element, index,
263: removed, added);
264: }
265:
266: private static void assertChildren(final Element element,
267: final int[] offsets, final AttributeSet[] attributes) {
268: DefStyledDoc_Helpers.assertChildren(element, offsets,
269: attributes);
270: }
271:
272: private DefaultDocumentEvent createEvent(final int offset,
273: final int length) {
274: event = doc.new DefaultDocumentEvent(offset, length,
275: EventType.CHANGE);
276: return event;
277: }
278:
279: private static List<?> getEdits(final DefaultDocumentEvent event) {
280: return DefStyledDoc_Helpers.getEdits(event);
281: }
282: }
|