This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 103467
Collapse All | Expand All

(-)a/openide.text/test/unit/src/org/openide/text/UndoRedoWrappingCooperationTest.java (+504 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * Contributor(s):
25
 *
26
 * The Original Software is NetBeans. The Initial Developer of the Original
27
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
28
 * Microsystems, Inc. All Rights Reserved.
29
 *
30
 * If you wish your version of this file to be governed by only the CDDL
31
 * or only the GPL Version 2, indicate your decision by adding
32
 * "[Contributor] elects to include this software in this distribution
33
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
34
 * single choice of license, a recipient has the option to distribute
35
 * your version of this file under either the CDDL, the GPL Version 2 or
36
 * to extend the choice of license to its licensees as provided above.
37
 * However, if you add GPL Version 2 code and therefore, elected the GPL
38
 * Version 2 license, then the option applies only if the new code is
39
 * made subject to such option by the copyright holder.
40
 */
41
42
43
package org.openide.text;
44
45
46
47
import java.io.IOException;
48
import javax.swing.event.UndoableEditEvent;
49
import javax.swing.event.UndoableEditListener;
50
import javax.swing.text.*;
51
import javax.swing.undo.CompoundEdit;
52
import javax.swing.undo.UndoableEdit;
53
import org.netbeans.junit.*;
54
import org.openide.awt.UndoRedo;
55
import org.openide.util.Exceptions;
56
57
/**
58
 * Emulating old UndoRedo manager deadlock.
59
 *
60
 * @author  Jaroslav Tulach
61
 */
62
public class UndoRedoWrappingCooperationTest extends NbTestCase implements CloneableEditorSupport.Env {
63
    static {
64
        System.setProperty("org.openide.windows.DummyWindowManager.VISIBLE", "false");
65
    }
66
    /** the support to work with */
67
    private CES support;
68
    // Env variables
69
    private String content = "Hello";
70
    private boolean valid = true;
71
    private boolean modified = false;
72
    /** if not null contains message why this document cannot be modified */
73
    private String cannotBeModified;
74
    private java.util.Date date = new java.util.Date ();
75
    private java.util.List/*<java.beans.PropertyChangeListener>*/ propL = new java.util.ArrayList ();
76
    private java.beans.VetoableChangeListener vetoL;
77
    
78
    /** Creates new TextTest */
79
    public UndoRedoWrappingCooperationTest (String s) {
80
        super(s);
81
    }
82
    
83
    protected javax.swing.text.EditorKit createEditorKit() {
84
        return new NbLikeEditorKit();
85
    }
86
87
    // Use these methods with the UndoRedoGroup patch
88
    CompoundEdit beginChunk(Document d) {
89
        // ur().beginUndoGroup();
90
        sendUndoableEdit(d, CloneableEditorSupport.BEGIN_COMIT_GROUP);
91
        return null;
92
    }
93
    
94
    void endChunk(Document d, CompoundEdit ce) {
95
        // ur().endUndoGroup();
96
        sendUndoableEdit(d, CloneableEditorSupport.END_COMIT_GROUP);
97
    }
98
99
    void sendUndoableEdit(Document d, UndoableEdit ue) {
100
        if(d instanceof AbstractDocument) {
101
            UndoableEditListener[] uels = ((AbstractDocument)d).getUndoableEditListeners();
102
            UndoableEditEvent ev = new UndoableEditEvent(d, ue);
103
            for(UndoableEditListener uel : uels) {
104
                uel.undoableEditHappened(ev);
105
            }
106
        }
107
    }
108
109
    // Use these methods with compound edit implementation
110
    // CompoundEdit beginChunk(Document d) {
111
    //     CompoundEdit ce = new CompoundEdit();
112
    //     support.getUndoRedo().undoableEditHappened
113
    //             (new UndoableEditEvent(d, ce));
114
    //     return ce;
115
    // }
116
117
    // void endChunk(Document d, CompoundEdit ce) {
118
    //     ce.end();
119
    // }
120
121
    UndoRedo.Manager ur() {
122
        return support.getUndoRedo();
123
    }
124
125
    protected void setUp () {
126
        support = new CES (this, org.openide.util.Lookup.EMPTY);
127
    }
128
129
    public void testTrivialChunk() throws Exception {
130
        content = "";
131
        StyledDocument d = support.openDocument();
132
133
        // same operations as testSingleChunk,
134
        // but don't test modified/canUndo/canRedo state
135
136
        CompoundEdit ce = beginChunk(d);
137
        d.insertString(d.getLength(), "a", null);
138
        d.insertString(d.getLength(), "b", null);
139
        endChunk(d, ce);
140
141
        assertEquals("data", "ab", d.getText(0, d.getLength()));
142
143
        ur().undo();
144
        assertEquals("after undo data", "", d.getText(0, d.getLength()));
145
146
        ur().redo();
147
        assertEquals("after redo data", "ab", d.getText(0, d.getLength()));
148
    }
149
150
    public void testSingleChunk() throws Exception {
151
        content = "";
152
        StyledDocument d = support.openDocument();
153
        assertFalse("initially: not modified", support.isModified());
154
        assertFalse("initially: no undo", ur().canUndo());
155
        assertFalse("initially: no redo", ur().canRedo());
156
157
        CompoundEdit ce = beginChunk(d);
158
        assertFalse("start chunk: not modified", support.isModified());
159
        assertFalse("start chunk: no undo", ur().canUndo());
160
        assertFalse("start chunk: no redo", ur().canRedo());
161
162
        d.insertString(d.getLength(), "a", null);
163
        assertTrue("insert: modified", support.isModified());
164
        assertTrue("insert: can undo", ur().canUndo());
165
        assertFalse("insert: no redo", ur().canRedo());
166
167
        d.insertString(d.getLength(), "b", null);
168
        endChunk(d, ce);
169
        assertEquals("chunk: data", "ab", d.getText(0, d.getLength()));
170
        assertTrue("endChunk: modified", support.isModified());
171
        assertTrue("endChunk: can undo", ur().canUndo());
172
        assertFalse("endChunk: no redo", ur().canRedo());
173
174
        ur().undo();
175
        assertEquals("after undo: data", "", d.getText(0, d.getLength()));
176
        assertFalse("undo: not modified", support.isModified());
177
        assertFalse("undo: no undo", ur().canUndo());
178
        assertTrue("undo: can redo", ur().canRedo());
179
180
        ur().redo();
181
        assertEquals("after redo: data", "ab", d.getText(0, d.getLength()));
182
        assertTrue("redo: modified", support.isModified());
183
        assertTrue("redo: can undo", ur().canUndo());
184
        assertFalse("redo: no redo", ur().canRedo());
185
    }
186
187
    public void testUndoWhileActiveChunk() throws Exception {
188
        content = "";
189
        StyledDocument d = support.openDocument();
190
        CompoundEdit ce = beginChunk(d);
191
        d.insertString(d.getLength(), "a", null);
192
        d.insertString(d.getLength(), "b", null);
193
194
        assertEquals("before undo: data", "ab", d.getText(0, d.getLength()));
195
196
        ur().undo();
197
198
        // These asserts assume that an undo in the middle of a chunk
199
        // is an undo on the whole chunk so far.
200
        // Different semantics could be defined, so that an undo inside
201
        // of a chunk affects the tiny pieces.
202
203
        assertEquals("after undo: data", "", d.getText(0, d.getLength()));
204
        assertFalse("after undo: not modified", support.isModified());
205
        assertFalse("after undo: no undo", ur().canUndo());
206
        assertTrue("after undo: can redo", ur().canRedo());
207
208
        // note still in the chunk.
209
210
        d.insertString(d.getLength(), "c", null);
211
        d.insertString(d.getLength(), "d", null);
212
        endChunk(d, ce);
213
214
        assertEquals("after endChunk: data", "cd", d.getText(0, d.getLength()));
215
        assertTrue("after endChunk: modified", support.isModified());
216
        assertTrue("after endChunk: can undo", ur().canUndo());
217
        assertFalse("after endChunk: no redo", ur().canRedo());
218
219
        
220
        ur().undo();
221
        assertEquals("undo after endChunk: data", "", d.getText(0, d.getLength()));
222
        assertFalse("undo after endChunk: not modified", support.isModified());
223
        assertFalse("undo after endChunk: no undo", ur().canUndo());
224
        assertTrue("undo after endChunk: can redo", ur().canRedo());
225
    }
226
227
    public void testSaveDocumentWhileActiveChunkCommon(boolean doFailCase) throws Exception {
228
        content = "";
229
        StyledDocument d = support.openDocument();
230
        CompoundEdit ce = beginChunk(d);
231
        d.insertString(d.getLength(), "a", null);
232
        d.insertString(d.getLength(), "b", null);
233
234
        support.saveDocument (); // creates a separate undoable chunk
235
        assertFalse("save: not modified", support.isModified());
236
        assertTrue("save: can undo", ur().canUndo());
237
        assertFalse("save: no redo", ur().canRedo());
238
239
        d.insertString(d.getLength(), "c", null);
240
        d.insertString(d.getLength(), "d", null);
241
        endChunk(d, ce);
242
243
        assertEquals("insert, after save: data", "abcd", d.getText(0, d.getLength()));
244
        assertTrue("insert, after save: modified", support.isModified());
245
        assertTrue("insert, after save: can undo", ur().canUndo());
246
        assertFalse("insert, after save: no redo", ur().canRedo());
247
248
        ur().undo();
249
        assertEquals("undo, at save: data", "ab", d.getText(0, d.getLength()));
250
        assertFalse("undo, at save: not modified", support.isModified());
251
        assertTrue("undo, at save: can undo", ur().canUndo());
252
        assertTrue("undo, at save: can redo", ur().canRedo());
253
254
        ur().undo();
255
        assertEquals("undo, before save: data", "", d.getText(0, d.getLength()));
256
257
        if(doFailCase) {
258
            // ****************************************************************
259
            // CES BUG???
260
            assertTrue("undo, before save: modified", support.isModified());
261
            // ****************************************************************
262
        }
263
264
        assertFalse("undo, before save: can undo", ur().canUndo());
265
        assertTrue("undo, before save: can redo", ur().canRedo());
266
267
        ur().redo();
268
        assertEquals("redo, at save: data", "ab", d.getText(0, d.getLength()));
269
        assertFalse("redo, at save: not modified", support.isModified());
270
        assertTrue("redo, at save: can undo", ur().canUndo());
271
        assertTrue("redo, at save: can redo", ur().canRedo());
272
    }
273
274
    public void testSaveDocumentWhileActiveChunk() throws Exception {
275
        testSaveDocumentWhileActiveChunkCommon(false);
276
    }
277
278
    // This fails, below is "testSaveDocumentErrorCase" without chunking,
279
    // it also fails.
280
    // public void testSaveDocumentWhileActiveChunkErroCase() throws Exception {
281
    //     testSaveDocumentWhileActiveChunkCommon(true);
282
    // }
283
284
    public void testNestedChunks() throws Exception {
285
        content = "";
286
        StyledDocument d = support.openDocument();
287
        CompoundEdit ce1 = beginChunk(d);
288
        d.insertString(d.getLength(), "a", null);
289
        d.insertString(d.getLength(), "b", null);
290
291
        CompoundEdit ce2 = beginChunk(d); // creates a separate undoable chunk
292
293
        d.insertString(d.getLength(), "c", null);
294
        d.insertString(d.getLength(), "d", null);
295
296
        endChunk(d, ce1);
297
298
        d.insertString(d.getLength(), "e", null);
299
        d.insertString(d.getLength(), "f", null);
300
301
        endChunk(d, ce2);
302
303
        assertEquals("data", "abcdef", d.getText(0, d.getLength()));
304
305
        // following fails if nesting not supported
306
        ur().undo();
307
        assertEquals("undo1", "abcd", d.getText(0, d.getLength()));
308
309
        ur().undo();
310
        assertEquals("undo2", "ab", d.getText(0, d.getLength()));
311
312
        ur().undo();
313
        assertEquals("undo3", "", d.getText(0, d.getLength()));
314
    }
315
316
    // This is testSaveDocumentWhileActiveChunk WITHOUT chunking
317
    public void testSaveDocumentCommon(boolean doFailCase) throws Exception {
318
        content = "";
319
        StyledDocument d = support.openDocument();
320
        d.insertString(d.getLength(), "a", null);
321
322
        support.saveDocument (); // creates a separate undoable chunk
323
        assertFalse("save: not modified", support.isModified());
324
        assertTrue("save: can undo", ur().canUndo());
325
        assertFalse("save: no redo", ur().canRedo());
326
327
        d.insertString(d.getLength(), "b", null);
328
329
        assertEquals("insert, after save: data", "ab", d.getText(0, d.getLength()));
330
        assertTrue("insert, after save: modified", support.isModified());
331
        assertTrue("insert, after save: can undo", ur().canUndo());
332
        assertFalse("insert, after save: no redo", ur().canRedo());
333
334
        ur().undo();
335
        assertEquals("undo, at save: data", "a", d.getText(0, d.getLength()));
336
        assertFalse("undo, at save: not modified", support.isModified());
337
        assertTrue("undo, at save: can undo", ur().canUndo());
338
        assertTrue("undo, at save: can redo", ur().canRedo());
339
340
        ur().undo();
341
        assertEquals("undo, before save: data", "", d.getText(0, d.getLength()));
342
343
        if(doFailCase) {
344
            // ****************************************************************
345
            // CES BUG???
346
            assertTrue("undo, before save: modified", support.isModified());
347
            // ****************************************************************
348
        }
349
350
        assertFalse("undo, before save: can undo", ur().canUndo());
351
        assertTrue("undo, before save: can redo", ur().canRedo());
352
353
        ur().redo();
354
        assertEquals("redo, at save: data", "a", d.getText(0, d.getLength()));
355
        assertFalse("redo, at save: not modified", support.isModified());
356
        assertTrue("redo, at save: can undo", ur().canUndo());
357
        assertTrue("redo, at save: can redo", ur().canRedo());
358
    }
359
360
    public void testSaveDocument() throws Exception {
361
        testSaveDocumentCommon(false);
362
    }
363
364
    public void testSaveDocumentErrorCase() throws Exception {
365
        testSaveDocumentCommon(true);
366
    }
367
368
    public void testRedoAfterSave() throws Exception {
369
        content = "";
370
        StyledDocument d = support.openDocument();
371
        d.insertString(d.getLength(), "a", null);
372
373
        d.insertString(d.getLength(), "b", null);
374
375
        assertEquals("insert: data", "ab", d.getText(0, d.getLength()));
376
        assertTrue("insert: modified", support.isModified());
377
        assertTrue("insert: can undo", ur().canUndo());
378
        assertFalse("insert: no redo", ur().canRedo());
379
380
        ur().undo();
381
        assertEquals("undo: data", "a", d.getText(0, d.getLength()));
382
        assertTrue("undo: modified", support.isModified());
383
        assertTrue("undo: can undo", ur().canUndo());
384
        assertTrue("undo: can redo", ur().canRedo());
385
386
        support.saveDocument ();
387
        assertFalse("save: not modified", support.isModified());
388
        assertTrue("save: can undo", ur().canUndo());
389
        assertTrue("save: can redo", ur().canRedo());
390
391
        ur().redo();
392
        assertEquals("redo: data", "ab", d.getText(0, d.getLength()));
393
        assertTrue("redo: modified", support.isModified());
394
        assertTrue("redo: can undo", ur().canUndo());
395
        assertFalse("redo: no redo", ur().canRedo());
396
    }
397
    
398
    //
399
    // Implementation of the CloneableEditorSupport.Env
400
    //
401
    
402
    public synchronized void addPropertyChangeListener(java.beans.PropertyChangeListener l) {
403
        propL.add (l);
404
    }    
405
    public synchronized void removePropertyChangeListener(java.beans.PropertyChangeListener l) {
406
        propL.remove (l);
407
    }
408
    
409
    public synchronized void addVetoableChangeListener(java.beans.VetoableChangeListener l) {
410
        assertNull ("This is the first veto listener", vetoL);
411
        vetoL = l;
412
    }
413
    public void removeVetoableChangeListener(java.beans.VetoableChangeListener l) {
414
        assertEquals ("Removing the right veto one", vetoL, l);
415
        vetoL = null;
416
    }
417
    
418
    public org.openide.windows.CloneableOpenSupport findCloneableOpenSupport() {
419
        return support;
420
    }
421
    
422
    public String getMimeType() {
423
        return "text/plain";
424
    }
425
    
426
    public java.util.Date getTime() {
427
        return date;
428
    }
429
    
430
    public java.io.InputStream inputStream() throws java.io.IOException {
431
        return new java.io.ByteArrayInputStream (content.getBytes ());
432
    }
433
    public java.io.OutputStream outputStream() throws java.io.IOException {
434
        class ContentStream extends java.io.ByteArrayOutputStream {
435
            public void close () throws java.io.IOException {
436
                super.close ();
437
                content = new String (toByteArray ());
438
            }
439
        }
440
        
441
        return new ContentStream ();
442
    }
443
    
444
    public boolean isValid() {
445
        return valid;
446
    }
447
    
448
    public boolean isModified() {
449
        return modified;
450
    }
451
452
    public void markModified() throws java.io.IOException {
453
        if (cannotBeModified != null) {
454
            IOException e = new IOException ();
455
            Exceptions.attachLocalizedMessage(e, cannotBeModified);
456
            throw e;
457
        }
458
        
459
        modified = true;
460
    }
461
    
462
    public void unmarkModified() {
463
        modified = false;
464
    }
465
466
    /** Implementation of the CES */
467
    private final class CES extends CloneableEditorSupport {
468
        public boolean plain;
469
        
470
        
471
        public CES (Env env, org.openide.util.Lookup l) {
472
            super (env, l);
473
        }
474
        
475
        protected String messageName() {
476
            return "Name";
477
        }
478
        
479
        protected String messageOpened() {
480
            return "Opened";
481
        }
482
        
483
        protected String messageOpening() {
484
            return "Opening";
485
        }
486
        
487
        protected String messageSave() {
488
            return "Save";
489
        }
490
        
491
        protected String messageToolTip() {
492
            return "ToolTip";
493
        }        
494
495
        protected javax.swing.text.EditorKit createEditorKit() {
496
            if (plain) {
497
                return super.createEditorKit ();
498
            } else {
499
                return UndoRedoWrappingCooperationTest.this.createEditorKit ();
500
            }
501
        }
502
    } // end of CES
503
504
}

Return to bug 103467