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.awt.font.TextAttribute;
023: import javax.swing.text.AbstractDocument.DefaultDocumentEvent;
024: import javax.swing.text.AbstractDocument.ElementEdit;
025: import junit.framework.TestCase;
026:
027: public class AbstractDocument_UpdateTest extends TestCase {
028: /**
029: * Event for last insertString.
030: */
031: DefaultDocumentEvent insert;
032:
033: /**
034: * Event for last remove.
035: */
036: DefaultDocumentEvent remove;
037:
038: /**
039: * Element edits for <code>root</code> ocurred when text was inserted.
040: */
041: ElementEdit insertEdit;
042:
043: /**
044: * Element edits for <code>root</code> ocurred when text was removed.
045: */
046: ElementEdit removeEdit;
047:
048: /**
049: * Root element for which element edits are tracked.
050: */
051: Element root;
052:
053: private AbstractDocument doc;
054:
055: /**
056: * String with three characters with right-to-left reading order.
057: */
058: static final String RTL = "\u05DC\u05DD\u05DE";
059:
060: /**
061: * String with three characters with left-to-right reading order.
062: */
063: static final String LTR = "abc";
064:
065: /**
066: * String with three digits.
067: */
068: static final String DIG = "012";
069:
070: @Override
071: protected void setUp() throws Exception {
072: super .setUp();
073: doc = new PlainDocument() {
074: private static final long serialVersionUID = 1L;
075:
076: @Override
077: protected void insertUpdate(
078: final DefaultDocumentEvent event,
079: final AttributeSet attrs) {
080: insert = event;
081: super .insertUpdate(event, attrs);
082: assertTrue(event.isInProgress());
083: // Get edits for root (bidi) element
084: insertEdit = (ElementEdit) insert.getChange(root);
085: }
086:
087: /**
088: * Overridden to catch first phase of remove update.
089: */
090: @Override
091: protected void removeUpdate(final DefaultDocumentEvent event) {
092: remove = event;
093: // Assert there's no paragraph changes so far
094: assertNull(remove
095: .getChange(doc.getDefaultRootElement()));
096: // Call PlainDocument.removeUpdate to fulfil processing
097: super .removeUpdate(event);
098: assertTrue(event.isInProgress());
099: }
100:
101: @Override
102: protected void postRemoveUpdate(
103: final DefaultDocumentEvent event) {
104: // Assert the event passed here is the same passed
105: // to removeUpdate
106: assertSame(remove, event);
107: // Assert there's no bidi structure changes so far
108: assertNull(remove.getChange(root));
109: super .postRemoveUpdate(event);
110: assertTrue(event.isInProgress());
111: // Get edit for root (bidi) element
112: removeEdit = (ElementEdit) remove.getChange(root);
113: }
114: };
115: // Use bidiRoot by default however it may be changed but
116: // all the test-methods must be updated
117: root = doc.getBidiRootElement();
118: }
119:
120: /**
121: * Returns bidi level of the element.
122: * @param e element to get bidi level from
123: * @return the bidi level
124: */
125: private static int getBidiLevel(final Element e) {
126: return StyleConstants.getBidiLevel(e.getAttributes());
127: }
128:
129: /**
130: * LTR text is inserted while default direction of doc is LTR
131: */
132: public void testInsertUpdate01() throws BadLocationException {
133: assertNull(doc.getProperty(TextAttribute.RUN_DIRECTION));
134: assertEquals(1, root.getElementCount());
135: assertEquals(0, getBidiLevel(root.getElement(0)));
136: doc.insertString(0, LTR, null);
137: assertEquals(1, root.getElementCount());
138: assertEquals(0, getBidiLevel(root.getElement(0)));
139: assertNull(insertEdit);
140: }
141:
142: /**
143: * RTL text is inserted while default direction of doc is LTR
144: */
145: public void testInsertUpdate02() throws BadLocationException {
146: assertNull(doc.getProperty(TextAttribute.RUN_DIRECTION));
147: assertEquals(1, root.getElementCount());
148: assertEquals(0, getBidiLevel(root.getElement(0)));
149: doc.insertString(0, RTL, null);
150: assertEquals(1, root.getElementCount());
151: assertEquals(1, getBidiLevel(root.getElement(0)));
152: assertEquals(1, insertEdit.getChildrenAdded().length);
153: assertEquals(1, getBidiLevel(insertEdit.getChildrenAdded()[0]));
154: assertEquals(1, insertEdit.getChildrenRemoved().length);
155: assertEquals(0,
156: getBidiLevel(insertEdit.getChildrenRemoved()[0]));
157: assertEquals(0, insertEdit.getIndex());
158: }
159:
160: /**
161: * DIG is inserted while default direction of doc is LTR
162: */
163: public void testInsertUpdate03() throws BadLocationException {
164: assertNull(doc.getProperty(TextAttribute.RUN_DIRECTION));
165: assertEquals(1, root.getElementCount());
166: assertEquals(0, getBidiLevel(root.getElement(0)));
167: doc.insertString(0, DIG, null);
168: assertEquals(1, root.getElementCount());
169: assertEquals(0, getBidiLevel(root.getElement(0)));
170: assertNull(insertEdit);
171: }
172:
173: /**
174: * LTR+RTL text is inserted while default direction of doc is LTR
175: */
176: public void testInsertUpdate04() throws BadLocationException {
177: assertNull(doc.getProperty(TextAttribute.RUN_DIRECTION));
178: assertEquals(1, root.getElementCount());
179: assertEquals(0, getBidiLevel(root.getElement(0)));
180: doc.insertString(0, LTR + RTL, null);
181: // LTR...RTL...\n (the latter is LTR either)
182: assertEquals(3, root.getElementCount());
183: assertEquals(0, getBidiLevel(root.getElement(0)));
184: assertEquals(1, getBidiLevel(root.getElement(1)));
185: assertEquals(0, getBidiLevel(root.getElement(2)));
186: assertEquals(3, insertEdit.getChildrenAdded().length);
187: assertEquals(1, insertEdit.getChildrenRemoved().length);
188: }
189:
190: /**
191: * RTL+LTR text is inserted while default direction of doc is LTR
192: */
193: public void testInsertUpdate05() throws BadLocationException {
194: assertNull(doc.getProperty(TextAttribute.RUN_DIRECTION));
195: assertEquals(1, root.getElementCount());
196: assertEquals(0, getBidiLevel(root.getElement(0)));
197: doc.insertString(0, RTL + LTR, null);
198: assertEquals(3, root.getElementCount());
199: assertEquals(1, getBidiLevel(root.getElement(0)));
200: assertEquals(2, getBidiLevel(root.getElement(1)));
201: assertEquals(1, getBidiLevel(root.getElement(2)));
202: assertEquals(3, insertEdit.getChildrenAdded().length);
203: assertEquals(1, insertEdit.getChildrenRemoved().length);
204: }
205:
206: /**
207: * DIG+RTL text is inserted while default direction of doc is LTR
208: */
209: public void testInsertUpdate06() throws BadLocationException {
210: assertNull(doc.getProperty(TextAttribute.RUN_DIRECTION));
211: assertEquals(1, root.getElementCount());
212: assertEquals(0, getBidiLevel(root.getElement(0)));
213: doc.insertString(0, DIG + RTL, null);
214: assertEquals(2, root.getElementCount());
215: assertEquals(2, getBidiLevel(root.getElement(0)));
216: assertEquals(1, getBidiLevel(root.getElement(1)));
217: assertEquals(2, insertEdit.getChildrenAdded().length);
218: assertEquals(1, insertEdit.getChildrenRemoved().length);
219: }
220:
221: /**
222: * RTL+DIG text is inserted while default direction of doc is LTR
223: */
224: public void testInsertUpdate07() throws BadLocationException {
225: assertNull(doc.getProperty(TextAttribute.RUN_DIRECTION));
226: assertEquals(1, root.getElementCount());
227: assertEquals(0, getBidiLevel(root.getElement(0)));
228: doc.insertString(0, RTL + DIG, null);
229: assertEquals(3, root.getElementCount());
230: assertEquals(1, getBidiLevel(root.getElement(0)));
231: assertEquals(2, getBidiLevel(root.getElement(1)));
232: assertEquals(1, getBidiLevel(root.getElement(2)));
233: assertEquals(3, insertEdit.getChildrenAdded().length);
234: assertEquals(1, insertEdit.getChildrenRemoved().length);
235: }
236:
237: /**
238: * Checks that bidi levels, and start and end offsets are equal to
239: * the expected ones
240: * @param root root element whose children are to compare
241: * @param levels expected bidi levels
242: * @param bounds expected start and end offsets
243: */
244: private static void checkLevelsAndBounds(final Element root,
245: final int[] levels, final int[] bounds) {
246: for (int i = 0; i < levels.length; i++) {
247: Element element = root.getElement(i);
248: int level = getBidiLevel(element);
249: assertEquals("Levels different at " + i, levels[i], level);
250: int start = element.getStartOffset();
251: int end = element.getEndOffset();
252: assertEquals("Start offset different at " + i, bounds[i],
253: start);
254: assertEquals("End offset different at " + i, bounds[i + 1],
255: end);
256: }
257: }
258:
259: /**
260: * LTR + RTL + DIG\nRTL + DIG + LTR\nDIG + RTL text is inserted
261: * while default direction of doc is LTR
262: */
263: public void testInsertUpdate08() throws BadLocationException {
264: assertNull(doc.getProperty(TextAttribute.RUN_DIRECTION));
265: assertEquals(1, root.getElementCount());
266: assertEquals(0, getBidiLevel(root.getElement(0)));
267: // Init document with two paragraphs of text
268: doc.insertString(0, LTR + RTL + DIG + "\n" + RTL + DIG + LTR
269: + "\n", null);
270: // Check the document has the expected structure
271: assertEquals(8, root.getElementCount());
272: checkLevelsAndBounds(root,
273: new int[] { 0, 1, 2, 0, 1, 2, 1, 0 }, new int[] { 0, 3,
274: 6, 9, 10, 13, 19, 20, 21 });
275: assertEquals(8, insertEdit.getChildrenAdded().length);
276: assertEquals(1, insertEdit.getChildrenRemoved().length);
277: assertEquals(0, insertEdit.getIndex());
278: // Add some more text at the end of document content
279: doc.insertString(doc.getLength(), DIG + RTL, null);
280: // Check the new document structure
281: assertEquals(9, root.getElementCount());
282: checkLevelsAndBounds(root, new int[] { 0, 1, 2, 0, 1, 2, 1, 2,
283: 1 }, new int[] { 0, 3, 6, 9, 10, 13, 19, 20, 23, 27 });
284: // Elements added "\n" of level 1 [19,20]
285: // DIG of level 2 [20,23]
286: // RTL of level 1 [23,27]
287: assertEquals(3, insertEdit.getChildrenAdded().length);
288: // Elements removed "\n" of level 1 [19,20]
289: // "\n" of level 0 [20,21]
290: assertEquals(2, insertEdit.getChildrenRemoved().length);
291: assertEquals(6, insertEdit.getIndex());
292: // Removed children thorough analysis (taking into account
293: // marks were moved when text was inserted)
294: Element[] removed = insertEdit.getChildrenRemoved();
295: assertEquals(1, getBidiLevel(removed[0]));
296: assertEquals(19, removed[0].getStartOffset());
297: assertEquals(26, removed[0].getEndOffset());
298: assertEquals(0, getBidiLevel(removed[1]));
299: assertEquals(26, removed[1].getStartOffset());
300: assertEquals(27, removed[1].getEndOffset());
301: }
302:
303: /**
304: * LTR+RTL+"\n"+LTR text is inserted while default direction of doc is LTR
305: */
306: public void testInsertUpdate09() throws BadLocationException {
307: doc.insertString(0, LTR + RTL + "\n" + LTR, null);
308: assertEquals(3, root.getElementCount());
309: checkLevelsAndBounds(root, new int[] { 0, 1, 0 }, new int[] {
310: 0, 3, 6, 11 });
311: }
312:
313: /**
314: * Tests if RUN_DIRECTION property has any influence on
315: * bidirectional algorithm in AbstractDocument.
316: */
317: public void testInsertUpdate10() throws BadLocationException {
318: doc.putProperty(TextAttribute.RUN_DIRECTION,
319: TextAttribute.RUN_DIRECTION_RTL);
320: doc.insertString(0, LTR, null);
321: assertEquals(2, root.getElementCount());
322: assertEquals(2, getBidiLevel(root.getElement(0)));
323: assertEquals(1, getBidiLevel(root.getElement(1)));
324: assertEquals(2, insertEdit.getChildrenAdded().length);
325: assertEquals(1, insertEdit.getChildrenRemoved().length);
326: }
327:
328: /**
329: * Tests if RUN_DIRECTION attribute set on text inserted has any
330: * influence on bidirectional algorithm in AbstractDocument.
331: */
332: public void testInsertUpdate11() throws BadLocationException {
333: StyleContext context = (StyleContext) doc.getAttributeContext();
334: doc.insertString(0, LTR, context.addAttribute(context
335: .getEmptySet(), TextAttribute.RUN_DIRECTION,
336: TextAttribute.RUN_DIRECTION_RTL));
337: assertEquals(1, root.getElementCount());
338: assertEquals(0, getBidiLevel(root.getElement(0)));
339: assertNull(insertEdit);
340: /*
341: // The assert section would be like this if document supported
342: // properties for paragraphs
343: assertEquals(2, root.getElementCount());
344: assertEquals(2, getBidiLevel(root.getElement(0)));
345: assertEquals(1, getBidiLevel(root.getElement(1)));
346:
347: assertEquals(2, insertEdit.getChildrenAdded().length);
348: assertEquals(1, insertEdit.getChildrenRemoved().length);
349: */
350: }
351:
352: /**
353: * Tests if RUN_DIRECTION property has any influence on
354: * bidirectional algorithm in AbstractDocument.
355: */
356: public void testInsertUpdate12() throws BadLocationException {
357: doc.insertString(0, "kkk", null);
358: doc.putProperty(TextAttribute.RUN_DIRECTION,
359: TextAttribute.RUN_DIRECTION_RTL);
360: doc.insertString(1, "rrr", null);
361: doc.replace(0, 6, "kkk", null);
362: assertEquals(2, root.getElementCount());
363: assertEquals(2, getBidiLevel(root.getElement(0)));
364: assertEquals(1, getBidiLevel(root.getElement(1)));
365: assertEquals(2, insertEdit.getChildrenAdded().length);
366: assertEquals(1, insertEdit.getChildrenRemoved().length);
367: }
368:
369: /**
370: * Tests that bidi information is updated whatever position text is
371: * inserted to.
372: */
373: public void testInsertUpdate13() throws BadLocationException {
374: assertEquals(0, doc.getLength());
375: doc.insertString(0, LTR, null);
376: assertEquals(1, root.getElementCount());
377: doc.insertString(doc.getLength(), RTL, null);
378: assertEquals(3, root.getElementCount());
379: assertEquals(0, getBidiLevel(root.getElement(0)));
380: assertEquals(1, getBidiLevel(root.getElement(1)));
381: assertEquals(0, getBidiLevel(root.getElement(2)));
382: }
383:
384: public void testRemoveUpdate01() throws BadLocationException {
385: doc.insertString(0, LTR, null);
386: doc.remove(0, 3);
387: assertEquals(1, root.getElementCount());
388: assertEquals(0, getBidiLevel(root.getElement(0)));
389: assertNull(removeEdit);
390: }
391:
392: public void testRemoveUpdate02() throws BadLocationException {
393: doc.insertString(0, RTL, null);
394: doc.remove(0, 3);
395: assertEquals(1, root.getElementCount());
396: assertEquals(0, getBidiLevel(root.getElement(0)));
397: assertEquals(1, removeEdit.getChildrenAdded().length);
398: assertEquals(1, removeEdit.getChildrenRemoved().length);
399: assertEquals(0, removeEdit.getIndex());
400: assertEquals(0, getBidiLevel(removeEdit.getChildrenAdded()[0]));
401: assertEquals(1,
402: getBidiLevel(removeEdit.getChildrenRemoved()[0]));
403: }
404:
405: public void testRemoveUpdate03() throws BadLocationException {
406: doc.insertString(0, DIG, null);
407: doc.remove(0, 3);
408: assertEquals(1, root.getElementCount());
409: assertEquals(0, getBidiLevel(root.getElement(0)));
410: assertNull(removeEdit);
411: }
412:
413: /**
414: * Test-method number isn't changed to correpond with
415: * testInsertUpdate08
416: */
417: public void testRemoveUpdate08() throws BadLocationException {
418: // Init document with three paragraphs of text
419: doc.insertString(0, LTR + RTL + DIG + "\n" + RTL + DIG + LTR
420: + "\n" + DIG + RTL, null);
421: assertEquals(9, root.getElementCount());
422: checkLevelsAndBounds(root, new int[] { 0, 1, 2, 0, 1, 2, 1, 2,
423: 1 }, new int[] { 0, 3, 6, 9, 10, 13, 19, 20, 23, 27 });
424: doc.remove(10, 3);
425: // Check the document has the expected structure
426: assertEquals(6, root.getElementCount());
427: checkLevelsAndBounds(root, new int[] { 0, 1, 2, 0, 2, 1 },
428: new int[] { 0, 3, 6, 9, 17, 20, 24 });
429: // Elements added: "\n" + DIG + LTR + "\n" of level 0 [9,17]
430: assertEquals(1, removeEdit.getChildrenAdded().length);
431: // Elements removed: "\n" of level 0 [ 9,10]
432: // RTL of level 1 [10,13]
433: // DIG + LTR of level 2 [13,19]
434: // "\n" of level 1 [19,20]
435: assertEquals(4, removeEdit.getChildrenRemoved().length);
436: assertEquals(3, removeEdit.getIndex());
437: // Removed children thorough analysis (taking into account
438: // marks were moved when text was inserted)
439: Element[] removed = removeEdit.getChildrenRemoved();
440: assertEquals(0, getBidiLevel(removed[0]));
441: assertEquals(1, getBidiLevel(removed[1]));
442: assertEquals(2, getBidiLevel(removed[2]));
443: assertEquals(1, getBidiLevel(removed[3]));
444: }
445:
446: public void testRemoveUpdate09() throws BadLocationException {
447: doc.insertString(0, LTR + RTL + DIG + RTL + DIG + LTR + DIG
448: + RTL, null);
449: assertEquals(8, root.getElementCount());
450: checkLevelsAndBounds(root,
451: new int[] { 0, 1, 2, 1, 2, 0, 1, 0 }, new int[] { 0, 3,
452: 6, 9, 12, 15, 21, 24, 25 });
453: doc.remove(0, doc.getLength());
454: assertEquals(1, root.getElementCount());
455: checkLevelsAndBounds(root, new int[] { 0 }, new int[] { 0, 1 });
456: }
457:
458: /**
459: * Tests that when text is removed from document, the paragraph where the
460: * change occurred is completely reanalized despite the fact that the text
461: * removed has only one direction and this operation actually doesn't
462: * cause structure change.
463: */
464: public void testRemoveUpdate10() throws BadLocationException {
465: doc.insertString(0, LTR + LTR + RTL + RTL + LTR + LTR, null);
466: assertEquals(3, root.getElementCount());
467: doc.remove(LTR.length() * 2, RTL.length());
468: assertEquals(3, root.getElementCount());
469: assertNotNull(removeEdit);
470: assertEquals(3, removeEdit.getChildrenAdded().length);
471: assertEquals(3, removeEdit.getChildrenRemoved().length);
472: }
473: }
|