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.lang.reflect.Field;
023: import java.util.HashMap;
024: import java.util.Vector;
025: import javax.swing.BasicSwingTestCase;
026: import javax.swing.UIManager;
027: import javax.swing.event.DocumentEvent;
028: import javax.swing.event.DocumentListener;
029: import javax.swing.event.UndoableEditEvent;
030: import javax.swing.event.UndoableEditListener;
031: import javax.swing.event.DocumentEvent.ElementChange;
032: import javax.swing.event.DocumentEvent.EventType;
033: import javax.swing.text.AbstractDocument.BranchElement;
034: import javax.swing.text.AbstractDocument.DefaultDocumentEvent;
035: import javax.swing.text.AbstractDocument.ElementEdit;
036: import javax.swing.undo.AbstractUndoableEdit;
037: import javax.swing.undo.CannotRedoException;
038: import javax.swing.undo.CannotUndoException;
039: import javax.swing.undo.UndoableEdit;
040: import junit.framework.TestCase;
041:
042: /**
043: * This class tests functions of AbstractDocument.DefaultDocumentEvent.
044: *
045: */
046: public class AbstractDocument_DefaultDocumentEventTest extends TestCase
047: implements DocumentListener, UndoableEditListener {
048: /**
049: * Document object used in tests.
050: */
051: AbstractDocument doc;
052:
053: /**
054: * Event for text insert.
055: */
056: DefaultDocumentEvent insert;
057:
058: /**
059: * Event for text remove.
060: */
061: DefaultDocumentEvent remove;
062:
063: /**
064: * Event for change in attributes.
065: */
066: DefaultDocumentEvent change;
067:
068: /**
069: * Undoable event.
070: */
071: UndoableEditEvent undoEvent;
072:
073: private static final String UNDO_TEXT_KEY = "AbstractDocument.undoText";
074:
075: private static final String REDO_TEXT_KEY = "AbstractDocument.redoText";
076:
077: private String undoName;
078:
079: private String redoName;
080:
081: /*
082: * @see TestCase#setUp()
083: */
084: @Override
085: protected void setUp() throws Exception {
086: super .setUp();
087: doc = new PlainDocument() {
088: private static final long serialVersionUID = 1L;
089:
090: @Override
091: protected void insertUpdate(
092: final DefaultDocumentEvent event,
093: final AttributeSet attrs) {
094: insert = event;
095: assertTrue(insert.isInProgress());
096: super .insertUpdate(event, attrs);
097: }
098:
099: @Override
100: protected void removeUpdate(final DefaultDocumentEvent event) {
101: remove = event;
102: assertTrue(remove.isInProgress());
103: super .removeUpdate(event);
104: }
105:
106: @Override
107: protected void postRemoveUpdate(
108: final DefaultDocumentEvent event) {
109: assertSame(remove, event);
110: super .postRemoveUpdate(event);
111: assertTrue(remove.isInProgress());
112: }
113: };
114: doc.insertString(0, "01234" + "\u05DC\u05DD\u05DE\u05DF\u05E0",
115: null);
116: doc.remove(3, 4);
117: change = doc.new DefaultDocumentEvent(0, 10,
118: DocumentEvent.EventType.CHANGE);
119: undoName = UIManager.getString(UNDO_TEXT_KEY);
120: redoName = UIManager.getString(REDO_TEXT_KEY);
121: }
122:
123: /**
124: * Test of basic functionality of addEdit method.
125: * @throws BadLocationException
126: */
127: public void testAddEdit01() throws BadLocationException {
128: // insert.isInProgress is false, so we can add no more edits
129: assertFalse(insert.addEdit(remove));
130: DefaultDocumentEvent edit = doc.new DefaultDocumentEvent(0, 10,
131: DocumentEvent.EventType.CHANGE);
132: assertTrue(edit.addEdit(insert));
133: assertTrue(edit.addEdit(remove));
134: assertEquals(2, getEdits(edit).size());
135: // Stop collecting and make undo
136: edit.end();
137: edit.undo();
138: // The document should be in its intial state
139: assertEquals("", doc.getText(0, doc.getLength()));
140: }
141:
142: private static HashMap<?, ?> getChanges(
143: final DefaultDocumentEvent event) {
144: try {
145: Field f = event.getClass().getDeclaredField("changes");
146: f.setAccessible(true);
147: return (HashMap<?, ?>) (f.get(event));
148: } catch (IllegalAccessException e) {
149: e.printStackTrace();
150: } catch (NoSuchFieldException e) {
151: e.printStackTrace();
152: }
153: return null;
154: }
155:
156: /**
157: * Internal only test to test switching to hashtable storage.
158: */
159: public void testAddEdit02() {
160: // Used as parent for Edits
161: final class Parent extends BranchElement {
162: private static final long serialVersionUID = 1L;
163:
164: public Parent() {
165: doc.super (null, null);
166: }
167: }
168: // Element edits
169: final class Child extends ElementEdit {
170: private static final long serialVersionUID = 1L;
171:
172: public boolean undone = false;
173:
174: public boolean redone = false;
175:
176: public Child(final Element parent) {
177: super (parent, 0, null, null);
178: }
179:
180: @Override
181: public void undo() {
182: undone = true;
183: }
184:
185: @Override
186: public void redo() {
187: redone = true;
188: }
189: }
190: DefaultDocumentEvent edit = doc.new DefaultDocumentEvent(0, 10,
191: EventType.CHANGE);
192: Parent[] parent = new Parent[15];
193: Child[] child = new Child[parent.length];
194: for (int i = 0; i < parent.length; i++) {
195: assertTrue("Can't add edit at " + i, edit
196: .addEdit(child[i] = new Child(
197: parent[i] = new Parent())));
198: if (BasicSwingTestCase.isHarmony()) {
199: if (i < 10) {
200: assertNull(getChanges(edit));
201: } else {
202: assertNotNull(getChanges(edit));
203: }
204: }
205: }
206: edit.addEdit((UndoableEdit) getEdits(edit).get(0));
207: edit.end();
208: // A new edit shouldn't be added 'cause we have called end()
209: assertFalse(edit.addEdit((UndoableEdit) getEdits(edit).get(1)));
210: edit.undo();
211: edit.redo();
212: // Do the check
213: for (int i = 0; i < parent.length; i++) {
214: ElementChange change = edit.getChange(parent[i]);
215: assertSame("Objects are not same at " + i, child[i], change);
216: assertTrue("Undo didn't get called at " + i,
217: child[i].undone);
218: assertTrue("Redo didn't get called at " + i,
219: child[i].redone);
220: }
221: assertEquals(16, getEdits(edit).size());
222: }
223:
224: private static Vector<?> getEdits(final DefaultDocumentEvent event) {
225: try {
226: Class<?> eventSuperClass = event.getClass().getSuperclass();
227: Field f = eventSuperClass.getDeclaredField("edits");
228: f.setAccessible(true);
229: return (Vector<?>) (f.get(event));
230: } catch (IllegalAccessException e) {
231: e.printStackTrace();
232: } catch (NoSuchFieldException e) {
233: e.printStackTrace();
234: }
235: return null;
236: }
237:
238: /*
239: * Class under test for String toString()
240: */
241: public void testToString() {
242: String ref = "[";
243: Vector<?> edits = getEdits(insert);
244: for (int i = 0; i < edits.size(); i++) {
245: AbstractUndoableEdit edit = (AbstractUndoableEdit) edits
246: .get(i);
247: if (i != 0) {
248: ref += ", ";
249: }
250: ref += edit.toString();
251: }
252: ref += "]";
253: assertEquals(ref, insert.toString());
254: }
255:
256: public void testGetUndoPresentationName() {
257: assertEquals(undoName + " " + insert.getPresentationName(),
258: insert.getUndoPresentationName());
259: assertEquals(undoName + " " + remove.getPresentationName(),
260: remove.getUndoPresentationName());
261: assertEquals(undoName + " " + change.getPresentationName(),
262: change.getUndoPresentationName());
263: }
264:
265: public void testGetUndoPresentationNameModified() {
266: UIManager.put(UNDO_TEXT_KEY, "ODNU");
267: try {
268: assertEquals(
269: "ODNU "
270: + UIManager
271: .getString("AbstractDocument.additionText"),
272: insert.getUndoPresentationName());
273: } finally {
274: UIManager.put(UNDO_TEXT_KEY, undoName);
275: }
276: }
277:
278: public void testGetRedoPresentationName() {
279: assertEquals(redoName + " " + insert.getPresentationName(),
280: insert.getRedoPresentationName());
281: assertEquals(redoName + " " + remove.getPresentationName(),
282: remove.getRedoPresentationName());
283: assertEquals(redoName + " " + change.getPresentationName(),
284: change.getRedoPresentationName());
285: }
286:
287: public void testGetRedoPresentationNameModified() {
288: UIManager.put(REDO_TEXT_KEY, "ODER");
289: try {
290: assertEquals(
291: "ODER "
292: + UIManager
293: .getString("AbstractDocument.additionText"),
294: insert.getRedoPresentationName());
295: } finally {
296: UIManager.put(REDO_TEXT_KEY, redoName);
297: }
298: }
299:
300: public void testGetPresentationName() {
301: assertSame(
302: UIManager.getString("AbstractDocument.additionText"),
303: insert.getPresentationName());
304: assertSame(
305: UIManager.getString("AbstractDocument.deletionText"),
306: remove.getPresentationName());
307: assertSame(UIManager
308: .getString("AbstractDocument.styleChangeText"), change
309: .getPresentationName());
310: }
311:
312: public void testIsSignificant() {
313: assertTrue(insert.isSignificant());
314: assertTrue(remove.isSignificant());
315: }
316:
317: public void testUndo01() throws BadLocationException {
318: remove.undo();
319: insert.undo();
320: assertEquals("", doc.getText(0, doc.getLength()));
321: assertEquals(1, doc.getBidiRootElement().getElementCount());
322: try {
323: insert.undo();
324: fail("CannotUndoException should be thrown");
325: } catch (CannotUndoException e) {
326: }
327: }
328:
329: public void testUndo02() throws BadLocationException {
330: final class UndoPlainDocument extends PlainDocument {
331: private static final long serialVersionUID = 1L;
332:
333: BranchElement altRoot = new BranchElement(null, null);
334:
335: boolean undone = false;
336:
337: boolean redone = false;
338:
339: @Override
340: protected void insertUpdate(
341: final DefaultDocumentEvent event,
342: final AttributeSet attrs) {
343: insert = event;
344: super .insertUpdate(event, attrs);
345: event.addEdit(new ElementEdit(altRoot, 0,
346: new Element[0], new Element[0]) {
347: private static final long serialVersionUID = 1L;
348:
349: @Override
350: public void undo() {
351: super .undo();
352: assertSame(Thread.currentThread(),
353: getCurrentWriter());
354: undone = true;
355: }
356:
357: @Override
358: public void redo() {
359: super .redo();
360: assertSame(Thread.currentThread(),
361: getCurrentWriter());
362: redone = true;
363: }
364: });
365: }
366: }
367: ;
368: doc = new UndoPlainDocument();
369: doc.insertString(0, "test", null);
370: ElementChange change = insert
371: .getChange(((UndoPlainDocument) doc).altRoot);
372: assertNotNull(change);
373: assertEquals(0, change.getChildrenAdded().length);
374: assertEquals(0, change.getChildrenRemoved().length);
375: // Additional assertions are in one of undo methods()
376: insert.undo();
377: assertTrue(((UndoPlainDocument) doc).undone);
378: assertFalse(((UndoPlainDocument) doc).redone);
379: // Additional assertions are in one of redo methods()
380: insert.redo();
381: assertTrue(((UndoPlainDocument) doc).redone);
382: }
383:
384: public void testUndo03() throws BadLocationException {
385: doc.remove(0, doc.getLength());
386: doc.addDocumentListener(this );
387: doc.addUndoableEditListener(this );
388: doc.insertString(0, "01234" + "\u05DC\u05DD\u05DE\u05DF\u05E0",
389: null);
390: doc.remove(3, 4);
391: // Save what we've got
392: DefaultDocumentEvent insertEvent = insert;
393: //Element insertChildrenAdded[] = insert.
394: DefaultDocumentEvent removeEvent = remove;
395: assertSame(undoEvent.getEdit(), remove);
396: insert = null;
397: remove = null;
398: undoEvent = null;
399: // Try to undo
400: removeEvent.undo();
401: assertNull(remove);
402: assertNotNull(insert);
403: assertNull(undoEvent);
404: DefaultDocumentEvent undoInsertEvent = insert;
405: insert = null;
406: insertEvent.undo();
407: assertNotNull(remove);
408: assertNull(insert);
409: assertNull(undoEvent);
410: DefaultDocumentEvent undoRemoveEvent = remove;
411: remove = null;
412: assertFalse(undoInsertEvent.canUndo());
413: assertTrue(undoInsertEvent.canRedo());
414: assertSame(insertEvent, undoRemoveEvent);
415: assertSame(EventType.INSERT, insertEvent.getType());
416: assertSame(EventType.INSERT, undoRemoveEvent.getType());
417: assertFalse(undoRemoveEvent.canUndo());
418: assertTrue(undoRemoveEvent.canRedo());
419: assertSame(removeEvent, undoInsertEvent);
420: assertSame(EventType.REMOVE, removeEvent.getType());
421: assertSame(EventType.REMOVE, undoInsertEvent.getType());
422: //undoInsertEvent.undo();
423: //insertEvent.redo();
424: //removeEvent.redo();
425: }
426:
427: public void testRedo() throws BadLocationException {
428: remove.undo();
429: insert.undo();
430: assertEquals("", doc.getText(0, doc.getLength()));
431: insert.redo();
432: remove.redo();
433: assertEquals("012\u05DE\u05DF\u05E0", doc.getText(0, doc
434: .getLength()));
435: assertEquals(2, doc.getBidiRootElement().getElementCount());
436: try {
437: remove.redo();
438: fail("CannotRedoException should be thrown");
439: } catch (CannotRedoException e) {
440: }
441: }
442:
443: public void testDefaultDocumentEvent() {
444: DefaultDocumentEvent event = doc.new DefaultDocumentEvent(10,
445: 7, DocumentEvent.EventType.CHANGE);
446: assertEquals(10, event.getOffset());
447: assertEquals(7, event.getLength());
448: assertSame(DocumentEvent.EventType.CHANGE, event.getType());
449: }
450:
451: /**
452: * The method getChange is used in setUp of
453: * AbstractDocument_ElementEditTest.
454: */
455: public void testGetChange() {
456: assertTrue(insert.getChange(doc.getBidiRootElement()) instanceof ElementEdit);
457: assertNull(insert.getChange(doc.getDefaultRootElement()));
458: }
459:
460: public void testGetDocument() {
461: assertSame(doc, insert.getDocument());
462: assertSame(doc, remove.getDocument());
463: }
464:
465: public void testGetType() {
466: assertSame(DocumentEvent.EventType.INSERT, insert.getType());
467: assertSame(DocumentEvent.EventType.REMOVE, remove.getType());
468: }
469:
470: public void testGetOffset() {
471: assertEquals(0, insert.getOffset());
472: assertEquals(3, remove.getOffset());
473: }
474:
475: public void testGetLength() {
476: assertEquals(10, insert.getLength());
477: assertEquals(4, remove.getLength());
478: }
479:
480: public void changedUpdate(final DocumentEvent event) {
481: fail("changeUpdate isn't supposed to be called");
482: }
483:
484: public void insertUpdate(final DocumentEvent event) {
485: insert = (DefaultDocumentEvent) event;
486: }
487:
488: public void removeUpdate(final DocumentEvent event) {
489: remove = (DefaultDocumentEvent) event;
490: }
491:
492: public void undoableEditHappened(final UndoableEditEvent event) {
493: undoEvent = event;
494: }
495: }
|