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.Rectangle;
023: import java.awt.Shape;
024: import java.util.ArrayList;
025: import javax.swing.BasicSwingTestCase;
026: import javax.swing.event.DocumentEvent;
027: import javax.swing.event.DocumentListener;
028: import javax.swing.event.DocumentEvent.ElementChange;
029: import javax.swing.event.DocumentEvent.EventType;
030: import javax.swing.text.CompositeView_ModelViewTest.ChildView;
031: import javax.swing.text.CompositeView_ModelViewTest.WithChildrenView;
032: import javax.swing.text.ViewTest.DisAbstractedView;
033: import javax.swing.text.ViewTestHelpers.ElementPartView;
034: import javax.swing.undo.UndoableEdit;
035: import junit.framework.TestCase;
036:
037: /**
038: * Tests changes-related methods of <code>View</code> class.
039: *
040: */
041: public class View_ChangesTest extends TestCase {
042: /**
043: * Class overriding some methods to test View behaviour in respect
044: * to {insert,remove,changed}Update.
045: */
046: private class ChangeView extends WithChildrenView {
047: /**
048: * The last allocation returned from
049: * <code>getChildAllocation</code>.
050: */
051: Shape childAllocation = null;
052:
053: public ChangeView(final Element element) {
054: super (element);
055: loadChildren(viewFactory);
056: viewsCreatedElements.clear();
057: replaceViews = null;
058: }
059:
060: @Override
061: public Shape getChildAllocation(final int index,
062: final Shape shape) {
063: if (!hasChildren) {
064: fail("getChildAllocation is not supposed to be "
065: + "called when there are no children");
066: }
067: return childAllocation = super .getChildAllocation(index,
068: shape);
069: }
070:
071: /**
072: * Returns a child from <code>children</code> or forwards
073: * to <code>super</code> depending on state of flag
074: * <code>hasChildren</code>.
075: */
076: @Override
077: public View getView(final int index) {
078: if (hasChildren) {
079: return super .getView(index);
080: }
081: return null;
082: }
083:
084: /**
085: * Returns <code>children.length</code> or forwards to
086: * <code>super</code> depending on state of flag
087: * <code>hasChildren</code>.
088: */
089: @Override
090: public int getViewCount() {
091: if (hasChildren) {
092: return super .getViewCount();
093: }
094: return 0;
095: }
096:
097: @Override
098: public void replace(final int index, final int length,
099: final View[] views) {
100: replaceIndex = index;
101: replaceLength = length;
102: replaceViews = views;
103: super .replace(index, length, views);
104: }
105:
106: /**
107: * Just a security check: <code>setParent</code> isn't called.
108: */
109: @Override
110: public void setParent(final View parent) {
111: super .setParent(parent);
112: fail("setParent is not supposed to be called");
113: }
114:
115: /**
116: * Check <code>forwardUpdate</code> parameters which is
117: * called from <code>insertUpdate</code>,
118: * <code>removeUpdate</code>, or <code>changedUpdate</code>.
119: */
120: @Override
121: protected void forwardUpdate(final ElementChange change,
122: final DocumentEvent event, final Shape shape,
123: final ViewFactory factory) {
124: forwardUpdateCalled = true;
125: if (updateChildrenReturn) {
126: assertSame(event.getChange(root), change);
127: } else {
128: assertNull(change);
129: }
130: assertSame(docEvent, event);
131: assertSame(rect, shape);
132: assertSame(viewFactory, factory);
133: super .forwardUpdate(change, event, shape, factory);
134: }
135:
136: /**
137: * Check <code>forwardUpdateToView</code> parameters which is
138: * called from <code>insertUpdate</code>,
139: * <code>removeUpdate</code>, or <code>changedUpdate</code>.
140: */
141: @Override
142: protected void forwardUpdateToView(final View view,
143: final DocumentEvent event, final Shape shape,
144: final ViewFactory factory) {
145: forwardUpdateToViewCalled = true;
146: viewsForwardedTo.add(view);
147: assertSame(docEvent, event);
148: assertSame(childAllocation, shape);
149: assertSame(viewFactory, factory);
150: super .forwardUpdateToView(view, event, shape, factory);
151: }
152:
153: /**
154: * Check <code>forwardUpdate</code> parameters which is
155: * called from <code>insertUpdate</code>,
156: * <code>removeUpdate</code>, or <code>changedUpdate</code>.
157: */
158: @Override
159: protected boolean updateChildren(final ElementChange change,
160: final DocumentEvent event, final ViewFactory factory) {
161: updateChildrenCalled = true;
162: assertSame(event.getChange(root), change);
163: assertSame(docEvent, event);
164: assertSame(viewFactory, factory);
165: assertTrue(super .updateChildren(change, event, factory));
166: assertFalse(forwardUpdateCalled);
167: assertFalse(updateLayoutCalled);
168: return updateChildrenReturn;
169: }
170:
171: /**
172: * Check <code>updateLayout</code> parameters which is called
173: * from <code>insertUpdate</code>, <code>removeUpdate</code>,
174: * or <code>changedUpdate</code>.
175: */
176: @Override
177: protected void updateLayout(final ElementChange change,
178: final DocumentEvent event, final Shape shape) {
179: updateLayoutCalled = true;
180: if (updateChildrenReturn) {
181: assertSame(event.getChange(root), change);
182: } else {
183: assertNull(change);
184: }
185: assertSame(docEvent, event);
186: assertSame(rect, shape);
187: super .updateLayout(change, event, shape);
188: }
189: }
190:
191: /**
192: * View allocation (Shape parameter).
193: */
194: private static final Rectangle rect = new Rectangle(20, 20);
195:
196: private Document doc;
197:
198: /**
199: * The event used to test the functionality.
200: */
201: private DocumentEvent docEvent;
202:
203: private boolean forwardUpdateCalled;
204:
205: private boolean forwardUpdateToViewCalled;
206:
207: /**
208: * Flag which controls whether anonymous test-view has children or not.
209: */
210: private boolean hasChildren;
211:
212: private Element line;
213:
214: /**
215: * Index of the first child where change happens (in call to replace).
216: */
217: private int replaceIndex;
218:
219: /**
220: * Number of elements to remove (in call to replace).
221: */
222: private int replaceLength;
223:
224: /**
225: * Views to add (in call to replace).
226: */
227: private View[] replaceViews;
228:
229: /**
230: * The root element where changes in document are tracked.
231: */
232: private Element root;
233:
234: private boolean updateChildrenCalled;
235:
236: /**
237: * Return value from updateChildren for anonymous test-view.
238: */
239: private boolean updateChildrenReturn;
240:
241: private boolean updateLayoutCalled;
242:
243: private View view;
244:
245: /**
246: * The view factory used in tests.
247: */
248: private ViewFactory viewFactory;
249:
250: /**
251: * List of elements for which new views were created.
252: */
253: private ArrayList<Element> viewsCreatedElements = new ArrayList<Element>();
254:
255: /**
256: * List of views for which forwardUpdateToView was called.
257: */
258: private ArrayList<View> viewsForwardedTo = new ArrayList<View>();
259:
260: /**
261: * Creates document event with type of <code>CHANGE</code>.
262: */
263: public void createChangeEvent() throws BadLocationException {
264: doc.insertString(doc.getLength(), "one\ntwo\n", null);
265: view.removeAll();
266: ((CompositeView) view).loadChildren(viewFactory);
267: viewsCreatedElements.clear();
268: replaceViews = null;
269: ElementChange change = docEvent.getChange(doc
270: .getDefaultRootElement());
271: docEvent = ((AbstractDocument) doc).new DefaultDocumentEvent(
272: docEvent.getLength(), docEvent.getOffset(),
273: EventType.CHANGE);
274: ((AbstractDocument.DefaultDocumentEvent) docEvent)
275: .addEdit((UndoableEdit) change);
276: }
277:
278: /**
279: * The view has <i>no</i> children, and <code>updateChildren</code>
280: * is <i>not</i> called as well as other methods involved.
281: */
282: public void testChangedUpdate01() throws BadLocationException {
283: createChangeEvent();
284: hasChildren = false;
285: assertEquals(0, view.getViewCount());
286: view.changedUpdate(docEvent, rect, viewFactory);
287: assertFalse(updateChildrenCalled);
288: assertFalse(forwardUpdateCalled);
289: assertFalse(forwardUpdateToViewCalled);
290: assertFalse(updateLayoutCalled);
291: }
292:
293: /**
294: * The view has children and <code>updateChildren</code> returns
295: * <code>false</code>.
296: */
297: public void testChangedUpdate02() throws BadLocationException {
298: hasChildren = true;
299: createChangeEvent();
300: updateChildrenReturn = false;
301: assertEquals(4, view.getViewCount());
302: view.changedUpdate(docEvent, rect, viewFactory);
303: assertTrue(updateChildrenCalled);
304: checkUpdatedChildren(4 + 2, 1);
305: assertTrue(forwardUpdateCalled);
306: assertTrue(forwardUpdateToViewCalled);
307: assertEquals(3, viewsForwardedTo.size()); // to all children
308: for (int i = 0; i < viewsForwardedTo.size(); i++) {
309: assertSame("@ " + i, view.getView(i + 1), viewsForwardedTo
310: .get(i));
311: }
312: assertTrue(updateLayoutCalled);
313: }
314:
315: /**
316: * The view has children and <code>updateChildren</code> returns
317: * <code>true</code>.
318: */
319: public void testChangedUpdate03() throws BadLocationException {
320: hasChildren = true;
321: createChangeEvent();
322: assertEquals(1, docEvent.getChange(root).getIndex());
323: updateChildrenReturn = true;
324: assertEquals(4, view.getViewCount());
325: view.changedUpdate(docEvent, rect, viewFactory);
326: assertTrue(updateChildrenCalled);
327: checkUpdatedChildren(4 + 2, 1);
328: assertTrue(forwardUpdateCalled);
329: assertFalse(forwardUpdateToViewCalled);
330: assertTrue(updateLayoutCalled);
331: }
332:
333: /**
334: * As if attributes are changed in the range 7-18:
335: * the second paragraph (6-15), and
336: * the third one (15, 19).
337: * <code>updateChilren</code> returns <code>true</code>
338: * (child views represent entire elements).
339: */
340: public void testChangedUpdate04() throws BadLocationException {
341: hasChildren = true;
342: changeDocument();
343: updateChildrenReturn = true;
344: Element prevLastLine = root
345: .getElement(root.getElementCount() - 2);
346: docEvent = ((AbstractDocument) doc).new DefaultDocumentEvent(
347: line.getStartOffset() + 1, prevLastLine.getEndOffset()
348: - 2 - line.getStartOffset(), EventType.CHANGE);
349: view.changedUpdate(docEvent, rect, viewFactory);
350: assertFalse(updateChildrenCalled);
351: assertTrue(forwardUpdateCalled);
352: assertTrue(forwardUpdateToViewCalled);
353: assertEquals(2, viewsForwardedTo.size());
354: for (int i = 0; i < viewsForwardedTo.size(); i++) {
355: assertSame("@ " + i, view.getView(i + 1), viewsForwardedTo
356: .get(i));
357: }
358: assertTrue(updateLayoutCalled);
359: }
360:
361: /**
362: * As if attributes are changed in the range 7-18:
363: * the second paragraph (6-15), and
364: * the third one (15, 19).
365: * <code>updateChilren</code> returns <code>false</code>
366: * (child views represent entire elements).
367: */
368: public void testChangedUpdate05() throws BadLocationException {
369: hasChildren = true;
370: changeDocument();
371: updateChildrenReturn = false;
372: Element prevLastLine = root
373: .getElement(root.getElementCount() - 2);
374: docEvent = ((AbstractDocument) doc).new DefaultDocumentEvent(
375: line.getStartOffset() + 1, prevLastLine.getEndOffset()
376: - 2 - line.getStartOffset(), EventType.CHANGE);
377: view.changedUpdate(docEvent, rect, viewFactory);
378: assertFalse(updateChildrenCalled);
379: assertTrue(forwardUpdateCalled);
380: assertTrue(forwardUpdateToViewCalled);
381: assertEquals(2, viewsForwardedTo.size());
382: for (int i = 0; i < viewsForwardedTo.size(); i++) {
383: assertSame("@ " + i, view.getView(i + 1), viewsForwardedTo
384: .get(i));
385: }
386: assertTrue(updateLayoutCalled);
387: }
388:
389: /**
390: * Tests <code>forwardUpdateToView</code> whether it calls
391: * {insert,remove,changed}Update depending on event type.
392: */
393: public void testForwardUpdateToView() {
394: // Class to store which function is called
395: class Params {
396: boolean change = false;
397:
398: boolean insert = false;
399:
400: boolean remove = false;
401: }
402: final Params params = new Params();
403: view = new DisAbstractedView(line);
404: View child = new DisAbstractedView(root.getElement(0)) {
405: @Override
406: public void changedUpdate(final DocumentEvent event,
407: final Shape shape, final ViewFactory factory) {
408: params.change = true;
409: }
410:
411: @Override
412: public void insertUpdate(final DocumentEvent event,
413: final Shape shape, final ViewFactory factory) {
414: params.insert = true;
415: }
416:
417: @Override
418: public void removeUpdate(final DocumentEvent event,
419: final Shape shape, final ViewFactory factory) {
420: params.remove = true;
421: }
422: };
423: view.forwardUpdateToView(child,
424: ((AbstractDocument) doc).new DefaultDocumentEvent(0, 0,
425: EventType.INSERT), rect, viewFactory);
426: assertTrue(params.insert);
427: params.insert = false;
428: assertFalse(params.remove);
429: params.remove = false;
430: assertFalse(params.change);
431: params.change = false;
432: view.forwardUpdateToView(child,
433: ((AbstractDocument) doc).new DefaultDocumentEvent(0, 0,
434: EventType.REMOVE), rect, viewFactory);
435: assertFalse(params.insert);
436: params.insert = false;
437: assertTrue(params.remove);
438: params.remove = false;
439: assertFalse(params.change);
440: params.change = false;
441: view.forwardUpdateToView(child,
442: ((AbstractDocument) doc).new DefaultDocumentEvent(0, 0,
443: EventType.CHANGE), rect, viewFactory);
444: assertFalse(params.insert);
445: params.insert = false;
446: assertFalse(params.remove);
447: params.remove = false;
448: assertTrue(params.change);
449: params.change = false;
450: view.forwardUpdateToView(child,
451: ((AbstractDocument) doc).new DefaultDocumentEvent(0, 0,
452: null), rect, viewFactory);
453: assertFalse(params.insert);
454: params.insert = false;
455: assertFalse(params.remove);
456: params.remove = false;
457: if (BasicSwingTestCase.isHarmony()) {
458: assertFalse(params.change);
459: params.change = false;
460: } else {
461: assertTrue(params.change);
462: params.change = false;
463: }
464: }
465:
466: /**
467: * The view has <i>no</i> children, and <code>updateChildren</code>
468: * is <i>not</i> called.
469: */
470: public void testInsertUpdate01() throws BadLocationException {
471: doc.insertString(line.getStartOffset() + 2, "one\ntwo\n", null);
472: hasChildren = false;
473: assertEquals(0, view.getViewCount());
474: view.insertUpdate(docEvent, rect, viewFactory);
475: assertFalse(updateChildrenCalled);
476: assertFalse(forwardUpdateCalled);
477: assertFalse(forwardUpdateToViewCalled);
478: assertFalse(updateLayoutCalled);
479: }
480:
481: /**
482: * The view has children and <code>updateChildren</code> returns
483: * <code>false</code>. (Views may represent parts of an Element.)
484: */
485: public void testInsertUpdate02() throws BadLocationException {
486: doc.insertString(line.getStartOffset() + 2, "one\ntwo\n", null);
487: hasChildren = true;
488: updateChildrenReturn = false;
489: assertEquals(2, view.getViewCount());
490: view.insertUpdate(docEvent, rect, viewFactory);
491: assertTrue(updateChildrenCalled);
492: checkUpdatedChildren(2 + 2, 1);
493: assertTrue(forwardUpdateCalled);
494: assertTrue(forwardUpdateToViewCalled);
495: assertEquals(4 - 1, viewsForwardedTo.size()); // first elem not affected
496: for (int i = 0; i < viewsForwardedTo.size(); i++) {
497: assertSame("@ " + i, view.getView(i + 1), viewsForwardedTo
498: .get(i));
499: }
500: assertTrue(updateLayoutCalled);
501: }
502:
503: /**
504: * The view has children and <code>updateChildren</code> returns
505: * <code>true</code>. (Views represent entire Elements.)
506: */
507: public void testInsertUpdate03() throws BadLocationException {
508: doc.insertString(line.getStartOffset() + 2, "one\ntwo\n", null);
509: hasChildren = true;
510: updateChildrenReturn = true;
511: assertEquals(2, view.getViewCount());
512: view.insertUpdate(docEvent, rect, viewFactory);
513: assertTrue(updateChildrenCalled);
514: checkUpdatedChildren(2 + 2, 1);
515: assertTrue(forwardUpdateCalled);
516: assertFalse(forwardUpdateToViewCalled);
517: assertTrue(updateLayoutCalled);
518: }
519:
520: /**
521: * Insert text so that structure changes occur at index of 2, while
522: * <code>updateChildren</code> returns <code>true</code>. The result
523: * is that changes must be forwarded to the first two view children.
524: */
525: public void testInsertUpdate04() throws BadLocationException {
526: hasChildren = true;
527: changeDocument();
528: // Event method will be tested upon
529: doc.insertString(doc.getLength(), "insert4", null);
530: assertEquals(2, docEvent.getChange(root).getIndex());
531: updateChildrenReturn = true;
532: assertEquals(4, view.getViewCount());
533: view.insertUpdate(docEvent, rect, viewFactory);
534: assertTrue(updateChildrenCalled);
535: checkUpdatedChildren(4 + 0, 2);
536: assertTrue(forwardUpdateCalled);
537: assertFalse(forwardUpdateToViewCalled);
538: assertTrue(updateLayoutCalled);
539: }
540:
541: /**
542: * No structural changes occurred to the <code>root</code> element.
543: * <code>updateChildren</code> must not be called in this case.
544: */
545: public void testInsertUpdate05() throws BadLocationException {
546: doc.insertString(line.getStartOffset() + 2, "one", null);
547: // This should not cause any line map restructure
548: assertNull(docEvent.getChange(root));
549: hasChildren = true;
550: updateChildrenReturn = true;
551: assertEquals(2, view.getViewCount());
552: view.insertUpdate(docEvent, rect, viewFactory);
553: assertFalse(updateChildrenCalled);
554: assertTrue(forwardUpdateCalled);
555: assertTrue(forwardUpdateToViewCalled);
556: assertEquals(1, viewsForwardedTo.size());
557: assertSame(view.getView(1), viewsForwardedTo.get(0));
558: assertTrue(updateLayoutCalled);
559: }
560:
561: /**
562: * <code>viewFactory</code> parameter is <code>null</code>.
563: */
564: public void testInsertUpdate06() throws BadLocationException {
565: doc.insertString(line.getStartOffset() + 2, "one\ntwo\n", null);
566: hasChildren = true;
567: updateChildrenReturn = true;
568: assertEquals(2, view.getViewCount());
569: try {
570: view.insertUpdate(docEvent, rect, viewFactory = null);
571: // So we should not check for this invalid parameter
572: // (viewFactory == null)
573: fail("Calling insertUpdate with null factory must result "
574: + " in exception");
575: } catch (NullPointerException e) {
576: }
577: assertTrue(updateChildrenCalled);
578: // The exception must have occurred in updateChildren
579: assertFalse(forwardUpdateCalled);
580: assertFalse(forwardUpdateToViewCalled);
581: assertFalse(updateLayoutCalled);
582: }
583:
584: /**
585: * <code>updateChildren</code> returns <code>true</code>.
586: * (Views represent entire elements.)
587: */
588: public void testInsertUpdate07() throws BadLocationException {
589: hasChildren = true;
590: changeDocument();
591: doc.insertString(2, "^^^\n", null);
592: assertEquals(0, docEvent.getChange(root).getIndex());
593: updateChildrenReturn = true;
594: assertEquals(4, view.getViewCount());
595: view.insertUpdate(docEvent, rect, viewFactory);
596: assertTrue(updateChildrenCalled);
597: checkUpdatedChildren(4 + 1, 1);
598: assertTrue(forwardUpdateCalled);
599: assertFalse(forwardUpdateToViewCalled);
600: assertTrue(updateLayoutCalled);
601: }
602:
603: /**
604: * <code>updateChildren</code> returns <code>false</code>.
605: * (Views represent partial elements.)
606: */
607: public void testInsertUpdate08() throws BadLocationException {
608: hasChildren = true;
609: changeDocument();
610: doc.insertString(2, "^^^\n", null);
611: assertEquals(0, docEvent.getChange(root).getIndex());
612: updateChildrenReturn = false;
613: assertEquals(4, view.getViewCount());
614: view.insertUpdate(docEvent, rect, viewFactory);
615: assertTrue(updateChildrenCalled);
616: checkUpdatedChildren(4 + 1, 1);
617: assertTrue(forwardUpdateCalled);
618: assertTrue(forwardUpdateToViewCalled);
619: assertEquals(2, viewsForwardedTo.size());
620: for (int i = 0; i < viewsForwardedTo.size(); i++) {
621: assertSame("@ " + i, view.getView(i), viewsForwardedTo
622: .get(i));
623: }
624: assertTrue(updateLayoutCalled);
625: }
626:
627: /**
628: * In this test view representing <code>line</code> is replaced with two
629: * view which represent parts of the <code>line</code> Element.
630: * <p>
631: * <code>updateChildren</code> returns <code>true</code>, i.e. it is
632: * considered a view represents an entire element.
633: */
634: public void testInsertUpdate09() throws BadLocationException {
635: createPartialViews();
636: updateChildrenReturn = true;
637: view.insertUpdate(docEvent, rect, viewFactory);
638: assertFalse(updateChildrenCalled);
639: assertTrue(forwardUpdateCalled);
640: assertTrue(forwardUpdateToViewCalled);
641: assertEquals(BasicSwingTestCase.isHarmony() ? 2 : 1,
642: viewsForwardedTo.size());
643: for (int i = 0; i < viewsForwardedTo.size(); i++) {
644: assertSame("@ " + i, view.getView(i + 1), viewsForwardedTo
645: .get(i));
646: assertTrue("@ " + i,
647: view.getView(i + 1) instanceof ElementPartView);
648: }
649: assertTrue(updateLayoutCalled);
650: }
651:
652: /**
653: * In this test view representing <code>line</code> is replaced with two
654: * view which represent parts of the <code>line</code> Element.
655: * (Same as in <code>testInsertUpdate09</code> except for the below).
656: * <p>
657: * <code>updateChildren</code> returns <code>false</code>, i.e. it is
658: * considered a view may represent a portion of element.
659: */
660: public void testInsertUpdate10() throws BadLocationException {
661: createPartialViews();
662: updateChildrenReturn = false;
663: view.insertUpdate(docEvent, rect, viewFactory);
664: assertFalse(updateChildrenCalled);
665: assertTrue(forwardUpdateCalled);
666: assertTrue(forwardUpdateToViewCalled);
667: assertEquals(BasicSwingTestCase.isHarmony() ? 2 : 1,
668: viewsForwardedTo.size());
669: for (int i = 0; i < viewsForwardedTo.size(); i++) {
670: assertSame("@ " + i, view.getView(i + 1), viewsForwardedTo
671: .get(i));
672: assertTrue("@ " + i,
673: view.getView(i + 1) instanceof ElementPartView);
674: }
675: assertTrue(updateLayoutCalled);
676: }
677:
678: private void createPartialViews() throws BadLocationException {
679: hasChildren = true;
680: changeDocument();
681: final int offset = (line.getStartOffset() + line.getEndOffset()) / 2;
682: doc.insertString(offset, "^^^^", null);
683: View[] parts = new View[2];
684: parts[0] = new ElementPartView(line, line.getStartOffset(),
685: offset + 2);
686: parts[1] = new ElementPartView(line, offset + 2, line
687: .getEndOffset());
688: view.replace(1, 1, parts);
689: }
690:
691: /**
692: * The view has <i>no</i> children, and <code>updateChildren</code>
693: * is <i>not</i> called as well as other methods involved.
694: */
695: public void testRemoveUpdate01() throws BadLocationException {
696: changeDocument();
697: doc.remove(line.getStartOffset(), 9);
698: hasChildren = false;
699: assertEquals(0, view.getViewCount());
700: view.removeUpdate(docEvent, rect, viewFactory);
701: assertFalse(updateChildrenCalled);
702: assertFalse(forwardUpdateCalled);
703: assertFalse(forwardUpdateToViewCalled);
704: assertFalse(updateLayoutCalled);
705: }
706:
707: /**
708: * The view has children and <code>updateChildren</code> returns
709: * <code>false</code>.
710: * <p>
711: * Exactly one element is removed.
712: */
713: public void testRemoveUpdate02() throws BadLocationException {
714: hasChildren = true;
715: changeDocument();
716: doc.remove(line.getStartOffset(), 9);
717: updateChildrenReturn = false;
718: assertEquals(4, view.getViewCount());
719: view.removeUpdate(docEvent, rect, viewFactory);
720: assertTrue(updateChildrenCalled);
721: checkUpdatedChildren(4 - 1, 2);
722: assertTrue(forwardUpdateCalled);
723: assertTrue(forwardUpdateToViewCalled);
724: assertEquals(2, viewsForwardedTo.size());
725: assertSame(view.getView(0), viewsForwardedTo.get(0));
726: assertSame(view.getView(1), viewsForwardedTo.get(1));
727: assertTrue(updateLayoutCalled);
728: }
729:
730: /**
731: * The view has children and <code>updateChildren</code> returns
732: * <code>true</code>.
733: * <p>
734: * Exactly one element is removed.
735: */
736: public void testRemoveUpdate03() throws BadLocationException {
737: hasChildren = true;
738: changeDocument();
739: doc.remove(line.getStartOffset(), 9);
740: updateChildrenReturn = true;
741: assertEquals(4, view.getViewCount());
742: view.removeUpdate(docEvent, rect, viewFactory);
743: assertTrue(updateChildrenCalled);
744: checkUpdatedChildren(4 - 1, 2);
745: assertTrue(forwardUpdateCalled);
746: assertTrue(forwardUpdateToViewCalled);
747: assertEquals(1, viewsForwardedTo.size());
748: assertSame(view.getView(0), viewsForwardedTo.get(0));
749: assertTrue(updateLayoutCalled);
750: }
751:
752: /**
753: * The view has children and <code>updateChildren</code> returns
754: * <code>true</code>.
755: * <p>
756: * Text removed is within one element.
757: */
758: public void testRemoveUpdate04() throws BadLocationException {
759: hasChildren = true;
760: changeDocument();
761: doc.remove(line.getStartOffset() + 1, 2);
762: updateChildrenReturn = true;
763: assertEquals(4, view.getViewCount());
764: view.removeUpdate(docEvent, rect, viewFactory);
765: assertFalse(updateChildrenCalled);
766: assertTrue(forwardUpdateCalled);
767: assertTrue(forwardUpdateToViewCalled);
768: assertEquals(1, viewsForwardedTo.size());
769: assertSame(view.getView(1), viewsForwardedTo.get(0));
770: assertTrue(updateLayoutCalled);
771: }
772:
773: /**
774: * The view has children and <code>updateChildren</code> returns
775: * <code>true</code>.
776: * <p>
777: * New line character is removed.
778: */
779: public void testRemoveUpdate05() throws BadLocationException {
780: hasChildren = true;
781: changeDocument();
782: doc.remove(line.getEndOffset() - 1, 1);
783: updateChildrenReturn = true;
784: assertEquals(4, view.getViewCount());
785: view.removeUpdate(docEvent, rect, viewFactory);
786: assertTrue(updateChildrenCalled);
787: checkUpdatedChildren(4 - 1, 2);
788: assertTrue(forwardUpdateCalled);
789: assertFalse(forwardUpdateToViewCalled);
790: // assertEquals(1, viewsForwardedTo.size());
791: // assertEquals(view.getView(1), viewsForwardedTo.get(0));
792: assertTrue(updateLayoutCalled);
793: }
794:
795: /**
796: * The view has children and <code>updateChildren</code> returns
797: * <code>false</code>.
798: * <p>
799: * New line character is removed.
800: */
801: public void testRemoveUpdate06() throws BadLocationException {
802: hasChildren = true;
803: changeDocument();
804: doc.remove(line.getEndOffset() - 1, 1);
805: updateChildrenReturn = false;
806: assertEquals(4, view.getViewCount());
807: view.removeUpdate(docEvent, rect, viewFactory);
808: assertTrue(updateChildrenCalled);
809: checkUpdatedChildren(4 - 1, 2);
810: assertTrue(forwardUpdateCalled);
811: assertTrue(forwardUpdateToViewCalled);
812: assertEquals(1, viewsForwardedTo.size());
813: assertSame(view.getView(1), viewsForwardedTo.get(0));
814: assertTrue(updateLayoutCalled);
815: }
816:
817: /**
818: * This test-method is similar to testRemoveUpdate02, but the text removed
819: * is in the first paragraph.
820: * <p>
821: * Exactly one element is removed.
822: */
823: public void testRemoveUpdate07() throws BadLocationException {
824: hasChildren = true;
825: changeDocument();
826: doc.remove(0, line.getStartOffset());
827: updateChildrenReturn = false;
828: assertEquals(4, view.getViewCount());
829: view.removeUpdate(docEvent, rect, viewFactory);
830: assertTrue(updateChildrenCalled);
831: checkUpdatedChildren(4 - 1, 2);
832: assertTrue(forwardUpdateCalled);
833: assertTrue(forwardUpdateToViewCalled);
834: assertEquals(1, viewsForwardedTo.size());
835: assertSame(view.getView(0), viewsForwardedTo.get(0));
836: assertTrue(updateLayoutCalled);
837: }
838:
839: /**
840: * This test-method is similar to testRemoveUpdate03, but the text removed
841: * is in the first paragraph.
842: * <p>
843: * Exactly one element is removed.
844: */
845: public void testRemoveUpdate08() throws BadLocationException {
846: hasChildren = true;
847: changeDocument();
848: doc.remove(0, line.getStartOffset());
849: updateChildrenReturn = true;
850: assertEquals(4, view.getViewCount());
851: view.removeUpdate(docEvent, rect, viewFactory);
852: assertTrue(updateChildrenCalled);
853: checkUpdatedChildren(4 - 1, 2);
854: assertTrue(forwardUpdateCalled);
855: assertFalse(forwardUpdateToViewCalled);
856: assertTrue(updateLayoutCalled);
857: }
858:
859: /**
860: * Tests <code>updateLayout</code> when element change is not
861: * <code>null</code>.
862: */
863: public void testUpdateLayout01() throws BadLocationException {
864: final class Params {
865: View child;
866:
867: boolean height;
868:
869: boolean width;
870: }
871: final Params params = new Params();
872: view = new DisAbstractedView(line) {
873: @Override
874: public void preferenceChanged(final View child,
875: final boolean width, final boolean height) {
876: params.child = child;
877: params.width = width;
878: params.height = height;
879: }
880: };
881: // Insert string to fill docEvent
882: doc.insertString(line.getStartOffset() + 2, "one\ntwo\n", null);
883: view.updateLayout(docEvent.getChange(root), docEvent, rect);
884: assertNull(params.child);
885: assertTrue(params.width);
886: assertTrue(params.height);
887: }
888:
889: /**
890: * Tests <code>updateLayout</code> when element change is
891: * <code>null</code>: seems like it has no side effects and
892: * probably does nothing in this case.
893: */
894: public void testUpdateLayout02() throws BadLocationException {
895: final boolean[] called = new boolean[1];
896: view = new DisAbstractedView(line) {
897: @Override
898: public void preferenceChanged(final View child,
899: final boolean width, final boolean height) {
900: called[0] = true;
901: }
902: };
903: // Insert string to fill docEvent
904: doc.insertString(line.getStartOffset() + 2, "one\ntwo\n", null);
905: view.updateLayout(null, docEvent, rect);
906: assertFalse(called[0]);
907: }
908:
909: /**
910: * Sets up the test fixture for changes tests.
911: */
912: @Override
913: protected void setUp() throws Exception {
914: super .setUp();
915: doc = new PlainDocument();
916: doc.insertString(0, "01234\nabcde", null);
917: root = doc.getDefaultRootElement();
918: line = root.getElement(1);
919: viewFactory = new ViewFactory() {
920: public View create(final Element element) {
921: viewsCreatedElements.add(element);
922: return new ChildView(element);
923: }
924: };
925: // We create anonymous subclass of View where we override
926: // update methods to assert parameters passed
927: view = new ChangeView(root);
928: // Document listener to catch events on insert and remove
929: // (so that they are real but not synthetic). But for event of
930: // type <code>CHANGE</code> we create it ourselves.
931: DocumentListener listener = new DocumentListener() {
932: public void changedUpdate(final DocumentEvent event) {
933: docEvent = event;
934: }
935:
936: public void insertUpdate(final DocumentEvent event) {
937: docEvent = event;
938: }
939:
940: public void removeUpdate(final DocumentEvent event) {
941: docEvent = event;
942: }
943: };
944: doc.addDocumentListener(listener);
945: CompositeView_ModelViewTest.shape = rect;
946: }
947:
948: private void changeDocument() throws BadLocationException {
949: doc.insertString(doc.getLength(), "one\ntwo\n", null);
950: line = root.getElement(1);
951: view.removeAll();
952: ((CompositeView) view).loadChildren(viewFactory);
953: viewsCreatedElements.clear();
954: replaceViews = null;
955: }
956:
957: /**
958: * Checks that child views were updated as expected.
959: *
960: * @param count the new number of children
961: * @param length the number of child views removed
962: */
963: private void checkUpdatedChildren(final int count, final int length) {
964: Element[] added = docEvent.getChange(root).getChildrenAdded();
965: assertEquals("added and created are different", added.length,
966: viewsCreatedElements.size());
967: for (int i = 0; i < added.length; i++) {
968: assertSame("Elements different @ " + i, added[i],
969: viewsCreatedElements.get(i));
970: }
971: assertEquals("Child view count is unexpected", count, view
972: .getViewCount());
973: assertEquals("Replace index is unexpected", docEvent.getChange(
974: root).getIndex(), replaceIndex);
975: assertEquals("Replace length is unexpected", length,
976: replaceLength);
977: assertEquals("Replace views.length is unexpected",
978: added.length, replaceViews.length);
979: }
980: /*public void testUpdateChildren() {
981: // tested in testInsertUpdate etc.
982: }
983:
984: public void testForwardUpdate() {
985: // tested in testInsertUpdate05
986: }*/
987: }
|