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 241991
Collapse All | Expand All

(-)a/openide.text/manifest.mf (-1 / +1 lines)
Lines 2-6 Link Here
2
OpenIDE-Module: org.openide.text
2
OpenIDE-Module: org.openide.text
3
OpenIDE-Module-Localizing-Bundle: org/openide/text/Bundle.properties
3
OpenIDE-Module-Localizing-Bundle: org/openide/text/Bundle.properties
4
AutoUpdate-Essential-Module: true
4
AutoUpdate-Essential-Module: true
5
OpenIDE-Module-Specification-Version: 6.60
5
OpenIDE-Module-Specification-Version: 6.61
6
6
(-)a/openide.text/nbproject/project.xml (-1 / +1 lines)
Lines 111-117 Link Here
111
                    <build-prerequisite/>
111
                    <build-prerequisite/>
112
                    <compile-dependency/>
112
                    <compile-dependency/>
113
                    <run-dependency>
113
                    <run-dependency>
114
                        <specification-version>6.15</specification-version>
114
                        <specification-version>6.70</specification-version>
115
                    </run-dependency>
115
                    </run-dependency>
116
                </dependency>
116
                </dependency>
117
            </module-dependencies>
117
            </module-dependencies>
(-)a/openide.text/src/org/openide/text/CloneableEditorSupport.java (-9 / +25 lines)
Lines 180-186 Link Here
180
    private UndoRedo.Manager undoRedo;
180
    private UndoRedo.Manager undoRedo;
181
181
182
    /** lines set for this object */
182
    /** lines set for this object */
183
    private Line.Set lineSet;
183
    private Line.Set[] lineSet = new Line.Set[] { null };
184
184
185
    /** Helper variable to prevent multiple cocurrent printing of this
185
    /** Helper variable to prevent multiple cocurrent printing of this
186
     * instance. */
186
     * instance. */
Lines 196-202 Link Here
196
    private Set<ChangeListener> listeners;
196
    private Set<ChangeListener> listeners;
197
197
198
    /** last selected editor pane. */
198
    /** last selected editor pane. */
199
    private transient Reference<Pane> lastSelected;
199
    private transient Reference<Pane> lastSelected[] = new Reference[] { null };
200
200
201
    /** The time of the last save to determine the real external modifications */
201
    /** The time of the last save to determine the real external modifications */
202
    private long lastSaveTime;
202
    private long lastSaveTime;
Lines 905-921 Link Here
905
905
906
        return null;
906
        return null;
907
    }
907
    }
908
909
    @Override
910
    protected void afterRedirect(CloneableOpenSupport redirectedTo) {
911
        super.afterRedirect(redirectedTo);
912
        // synchronize field from redirected instance, i.e. for correct getOpenedPanes answers
913
        if (redirectedTo instanceof CloneableEditorSupport) {
914
            CloneableEditorSupport other = ((CloneableEditorSupport)redirectedTo);
915
            this.lastSelected = other.lastSelected;
916
            this.openClose = other.openClose;
917
            this.lineSet = other.lineSet;
918
        }
919
        // notify EditorCookie.Observable listeners if any
920
        if (propertyChangeSupport != null) {
921
            propertyChangeSupport.firePropertyChange(EditorCookie.Observable.PROP_OPENED_PANES, null, null);
922
        }
923
    }
908
    
924
    
909
    /** Returns the lastly selected Pane or null
925
    /** Returns the lastly selected Pane or null
910
     */
926
     */
911
    final Pane getLastSelected() {
927
    final Pane getLastSelected() {
912
        Reference<Pane> r = lastSelected;
928
        Reference<Pane> r = lastSelected[0];
913
929
914
        return (r == null) ? null : r.get();
930
        return (r == null) ? null : r.get();
915
    }
931
    }
916
932
917
    final void setLastSelected(Pane lastSelected) {
933
    final void setLastSelected(Pane lastSelected) {
918
        this.lastSelected = new WeakReference<Pane>(lastSelected);
934
        this.lastSelected[0] = new WeakReference<Pane>(lastSelected);
919
    }
935
    }
920
936
921
    //
937
    //
Lines 1639-1657 Link Here
1639
    */
1655
    */
1640
    Line.Set updateLineSet(boolean clear) {
1656
    Line.Set updateLineSet(boolean clear) {
1641
        synchronized (getLock()) {
1657
        synchronized (getLock()) {
1642
            if ((lineSet != null) && !clear) {
1658
            if ((lineSet[0] != null) && !clear) {
1643
                return lineSet;
1659
                return lineSet[0];
1644
            }
1660
            }
1645
1661
1646
            if ((getDoc() == null) ||
1662
            if ((getDoc() == null) ||
1647
                (openClose.getDocumentStatusLA() == DocumentStatus.RELOADING))
1663
                (openClose.getDocumentStatusLA() == DocumentStatus.RELOADING))
1648
            {
1664
            {
1649
                lineSet = new EditorSupportLineSet.Closed(CloneableEditorSupport.this);
1665
                lineSet[0] = new EditorSupportLineSet.Closed(CloneableEditorSupport.this);
1650
            } else {
1666
            } else {
1651
                lineSet = new EditorSupportLineSet(CloneableEditorSupport.this,getDoc());
1667
                lineSet[0] = new EditorSupportLineSet(CloneableEditorSupport.this,getDoc());
1652
            }
1668
            }
1653
1669
1654
            return lineSet;
1670
            return lineSet[0];
1655
        }
1671
        }
1656
    }
1672
    }
1657
1673
(-)a/openide.text/test/unit/src/org/openide/text/CloneableEditorSupportCOSRedirectorTest.java (+402 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * Contributor(s):
28
 *
29
 * The Original Software is NetBeans.
30
 * Portions Copyrighted 2007 Sun Microsystems, Inc.
31
 */
32
package org.openide.text;
33
34
import java.awt.GraphicsEnvironment;
35
import java.beans.PropertyChangeEvent;
36
import java.beans.PropertyChangeListener;
37
import java.io.ByteArrayOutputStream;
38
import java.io.InputStream;
39
import java.lang.ref.WeakReference;
40
import java.util.Arrays;
41
import java.util.concurrent.atomic.AtomicBoolean;
42
import javax.swing.SwingUtilities;
43
import javax.swing.text.Document;
44
import javax.swing.text.EditorKit;
45
import junit.framework.Test;
46
import junit.framework.TestSuite;
47
import org.netbeans.junit.MockServices;
48
import org.netbeans.junit.NbTestCase;
49
import org.openide.DialogDescriptor;
50
import org.openide.DialogDisplayer;
51
import org.openide.NotifyDescriptor;
52
import org.openide.cookies.EditorCookie;
53
import org.openide.util.Lookup;
54
import org.openide.util.lookup.AbstractLookup;
55
import org.openide.util.lookup.InstanceContent;
56
import org.openide.windows.CloneableOpenSupport;
57
import org.openide.windows.CloneableOpenSupportRedirector;
58
59
/**
60
 * based on functionality from CloneableEditorSupportRedirectorTest
61
 * @author Vladimir Voskresensky
62
 */
63
public class CloneableEditorSupportCOSRedirectorTest extends NbTestCase
64
implements CloneableEditorSupport.Env {
65
66
    public static Test suite() {
67
        return GraphicsEnvironment.isHeadless() ? new TestSuite() : new TestSuite(CloneableEditorSupportCOSRedirectorTest.class);
68
    }
69
70
    static {
71
        System.setProperty("org.openide.windows.DummyWindowManager.VISIBLE", "false");
72
    }
73
    /** the content of lookup of support */
74
    private InstanceContent ic;
75
    private Redirector red;
76
    private DialogDisplayer dd;
77
78
    
79
    // Env variables
80
    private final StringBuilder content;
81
    private boolean modified = false;
82
    private final java.util.Date date = new java.util.Date ();
83
    private java.util.List<PropertyChangeListener> propL = new java.util.ArrayList<PropertyChangeListener>();
84
    private java.beans.VetoableChangeListener vetoL;
85
86
    
87
    
88
    public CloneableEditorSupportCOSRedirectorTest(String testName) {
89
        super(testName);
90
        this.content = new StringBuilder("");
91
    }
92
93
    public CloneableEditorSupportCOSRedirectorTest(StringBuilder content) {
94
        super("");
95
        this.content = content;
96
    }
97
    
98
    protected void setUp () {
99
        ic = new InstanceContent ();
100
        CES support = new CES (this, new AbstractLookup(ic));
101
        
102
        MockServices.setServices(Redirector.class, DD.class);
103
        red = Lookup.getDefault().lookup(Redirector.class);
104
        assertNotNull(red);
105
        dd = Lookup.getDefault().lookup(DD.class);
106
        assertNotNull(dd);
107
108
        CloneableEditorSupportCOSRedirectorTest t = new CloneableEditorSupportCOSRedirectorTest(this.content);
109
        red.master = support;
110
        InstanceContent slave = new InstanceContent();
111
        red.slave = new CES(t, new AbstractLookup (slave));
112
        slave.add(red.master);
113
    }
114
115
    @Override
116
    protected void tearDown() throws Exception {
117
        super.tearDown(); 
118
        red.master.close();
119
        red.slave.close();     
120
        content.delete(0, content.length());
121
    }
122
        
123
    public void testSameDocument() throws Exception {    
124
        red.master.open();
125
        red.slave.open();
126
        javax.swing.text.Document doc = red.slave.openDocument ();
127
        assertNotNull (doc);
128
        
129
        assertSame(doc, red.master.getDocument());
130
        
131
        String s = doc.getText (0, doc.getLength ());
132
        assertEquals ("Same text as in the stream", content.toString(), s);
133
        
134
        assertFalse ("No redo", red.slave.getUndoRedo ().canRedo ());
135
        assertFalse ("No undo", red.slave.getUndoRedo ().canUndo ());
136
    }
137
    
138
    public void testLineLookupIsPropagated () throws Exception {
139
        content.append("Line1\nLine2\n");
140
        red.master.open();
141
        red.slave.open();
142
        Integer template = new Integer (1);
143
        ic.add (template); // put anything into the lookup
144
        
145
        // in order to set.getLines() work correctly, the document has to be loaded
146
        red.master.openDocument();
147
        
148
        Line.Set set = red.master.getLineSet();
149
        assertSame("Same lines", set, red.slave.getLineSet());
150
        java.util.List list = set.getLines();
151
        assertEquals ("Three lines", 3, list.size ());
152
        
153
        Line l = (Line)list.get (0);
154
        Integer i = l.getLookup ().lookup (Integer.class);
155
        assertEquals ("The original integer", template, i);
156
        ic.remove (template);
157
        i = l.getLookup ().lookup (Integer.class);
158
        assertNull ("Lookup is dynamic, so now there is nothing", i);
159
    }
160
    
161
    
162
    public void testGetInputStream () throws Exception {
163
        content.append("goes\nto\nInputStream");
164
        red.master.open();
165
        red.slave.open();
166
        String added = "added before\n";
167
        javax.swing.text.Document doc = red.master.openDocument ();
168
        assertNotNull (doc);
169
        
170
        // modify the document
171
        doc.insertString(0, added, null);
172
        compareStreamWithString(red.master.getInputStream(), added + content);
173
        compareStreamWithString(red.slave.getInputStream(), added + content);
174
    }
175
    
176
    public void testGetInputStreamWhenClosed () throws Exception {
177
        content.append("basic\ncontent");
178
        red.master.open();
179
        red.slave.open();
180
        compareStreamWithString(red.master.getInputStream(), content);
181
        compareStreamWithString(red.slave.getInputStream(), content);
182
        // we should be doing this with the document still closed 
183
        assertNull("The document is supposed to be still closed", red.master.getDocument ());
184
    }
185
    
186
    public void testDocumentCanBeGarbageCollectedWhenClosed () throws Exception {
187
        content.append("Ahoj\nMyDoc");
188
        red.master.open();
189
        red.slave.open();
190
        javax.swing.text.Document doc = red.master.openDocument ();
191
        assertNotNull (doc);
192
        
193
        assertTrue ("Document is loaded", red.master.isDocumentLoaded ());
194
        assertTrue ("Document is loaded", red.slave.isDocumentLoaded ());
195
        assertTrue ("Can be closed without problems", red.slave.close ());
196
        assertFalse ("Document is not loaded", red.master.isDocumentLoaded ());
197
        assertFalse ("Document is not loaded", red.slave.isDocumentLoaded ());
198
        
199
        WeakReference<?> ref = new WeakReference<Document>(doc);
200
        doc = null;
201
        
202
        assertGC ("Document can dissapear", ref);
203
    }
204
205
    /**
206
     * Tests that the wrapEditorComponent() method returns the passed
207
     * parameter (doesn't wrap the passed component in some additional UI).
208
     */
209
    public void testWrapEditorComponent() {
210
        javax.swing.JPanel panel = new javax.swing.JPanel();
211
        assertSame(red.master.wrapEditorComponent(panel), panel);
212
        assertSame(red.slave.wrapEditorComponent(panel), panel);
213
    }
214
215
    public void testAfterOpenOfSlaveThereArePanesAndEvent() throws Exception {
216
        red.master.open();
217
        final AtomicBoolean wasNonEmtpyOpenedPanesEvent = new AtomicBoolean(false);
218
        final AtomicBoolean emtpyPanes = new AtomicBoolean(false);
219
        final AtomicBoolean nonEmtpyPanes = new AtomicBoolean(false);
220
        
221
        PropertyChangeListener l = new PropertyChangeListener() {
222
223
            @Override
224
            public void propertyChange(PropertyChangeEvent evt) {
225
                if (EditorCookie.Observable.PROP_OPENED_PANES.equals(evt.getPropertyName())) {
226
                    wasNonEmtpyOpenedPanesEvent.set(red.slave.getOpenedPanes() != null);
227
                }
228
            }
229
230
        };
231
        red.slave.addPropertyChangeListener(l);
232
        
233
        class Check implements Runnable {
234
            @Override
235
            public void run() {
236
                // editor not yet opened, attach listener and open from there
237
                emtpyPanes.set(red.slave.getOpenedPanes() == null);
238
                red.slave.open();
239
                nonEmtpyPanes.set(red.slave.getOpenedPanes() != null);
240
            }
241
        }
242
        Check check = new Check();
243
        
244
        SwingUtilities.invokeAndWait(check);
245
        red.slave.removePropertyChangeListener(l);
246
        assertTrue("No panes are open before red.slave.open", emtpyPanes.get());
247
        assertTrue("Some panes are now open after red.slave.open", nonEmtpyPanes.get());
248
        assertTrue("PROP_OPENED_PANES event was not fired", wasNonEmtpyOpenedPanesEvent.get());
249
    }
250
251
    public void testGetEditorKit() {
252
        EditorKit kit = CloneableEditorSupport.getEditorKit("text/plain");
253
        assertNotNull("EditorKit should never be null", kit);
254
        // There shouldn't be any EK registered and we should get the default one
255
        assertEquals("Wrong default EditorKit", "org.openide.text.CloneableEditorSupport$PlainEditorKit", kit.getClass().getName());
256
    }
257
    
258
    private void compareStreamWithString(InputStream is, CharSequence s) throws Exception{
259
        int i;
260
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
261
        while ((i = is.read()) != -1) {
262
            baos.write(i);
263
        }
264
        byte b1[] = baos.toByteArray();
265
        byte b2[] = s.toString().getBytes();
266
        assertTrue("Same bytes as would result from the string: " + s, Arrays.equals(b1, b2));
267
    }
268
    
269
    //
270
    // Implementation of the CloneableEditorred.master.Env
271
    //
272
    
273
    public synchronized void addPropertyChangeListener(java.beans.PropertyChangeListener l) {
274
        propL.add (l);
275
    }    
276
    public synchronized void removePropertyChangeListener(java.beans.PropertyChangeListener l) {
277
        propL.remove (l);
278
    }
279
    
280
    public synchronized void addVetoableChangeListener(java.beans.VetoableChangeListener l) {
281
        assertNull ("This is the first veto listener", vetoL);
282
        vetoL = l;
283
    }
284
    public void removeVetoableChangeListener(java.beans.VetoableChangeListener l) {
285
        assertEquals ("Removing the right veto one", vetoL, l);
286
        vetoL = null;
287
    }
288
    
289
    public org.openide.windows.CloneableOpenSupport findCloneableOpenSupport() {
290
        return red.master;
291
    }
292
    
293
    public String getMimeType() {
294
        return "text/plain";
295
    }
296
    
297
    public java.util.Date getTime() {
298
        return date;
299
    }
300
    
301
    public java.io.InputStream inputStream() throws java.io.IOException {
302
        return new java.io.ByteArrayInputStream (content.toString().getBytes ());
303
    }
304
    public java.io.OutputStream outputStream() throws java.io.IOException {
305
        class ContentStream extends java.io.ByteArrayOutputStream {
306
            public void close () throws java.io.IOException {
307
                super.close ();
308
                content.append(new String (toByteArray ()));
309
            }
310
        }
311
        
312
        return new ContentStream ();
313
    }
314
    
315
    public boolean isValid() {
316
        return true;
317
    }
318
    
319
    public boolean isModified() {
320
        return modified;
321
    }
322
323
    public void markModified() throws java.io.IOException {
324
        modified = true;
325
    }
326
    
327
    public void unmarkModified() {
328
        modified = false;
329
    }
330
331
    /** Implementation of the CES */
332
    private static final class CES extends CloneableEditorSupport {
333
        public CES (Env env, Lookup l) {
334
            super (env, l);
335
        }
336
337
        @Override
338
        protected boolean asynchronousOpen() {
339
            return true;
340
        }
341
        
342
        protected String messageName() {
343
            return "Name";
344
        }
345
        
346
        protected String messageOpened() {
347
            return "Opened";
348
        }
349
        
350
        protected String messageOpening() {
351
            return "Opening";
352
        }
353
        
354
        protected String messageSave() {
355
            return "Save";
356
        }
357
        
358
        protected String messageToolTip() {
359
            return "ToolTip";
360
        }
361
        
362
    }
363
364
    
365
    public static final class Redirector extends CloneableOpenSupportRedirector {
366
        CES master;
367
        CES slave;
368
369
        @Override
370
        protected CloneableOpenSupport redirect(CloneableOpenSupport.Env env) {
371
            if (env == slave.cesEnv()) {
372
                return master;
373
            }
374
            return null;
375
        }
376
377
        @Override
378
        protected void opened(CloneableOpenSupport.Env env) {
379
        }
380
381
        @Override
382
        protected void closed(CloneableOpenSupport.Env env) {
383
        }
384
    }
385
    /**
386
     * Our own dialog displayer when modified CES is closed we agree to close it.
387
     */
388
    public static final class DD extends DialogDisplayer {
389
390
        public static Object[] options;
391
        public static Object toReturn;
392
        public static boolean disableTest;
393
394
        public java.awt.Dialog createDialog(DialogDescriptor descriptor) {
395
            throw new IllegalStateException("Not implemented");
396
        }
397
398
        public Object notify(NotifyDescriptor descriptor) {
399
            return NotifyDescriptor.CLOSED_OPTION;
400
        }
401
    } // end of DD    
402
}
(-)a/openide.windows/apichanges.xml (+15 lines)
Lines 50-55 Link Here
50
<apidef name="winsys">Window System API</apidef>
50
<apidef name="winsys">Window System API</apidef>
51
</apidefs>
51
</apidefs>
52
<changes>
52
<changes>
53
<change id="COS_afterRedirect">
54
    <api name="winsys"/>
55
    <summary>Added method afterRedirect(CloneableOpenSupport) to CloneableOpenSupport</summary>
56
    <version major="6" minor="70"/>
57
    <date day="20" month="2" year="2014"/>
58
    <author login="vv159170"/>
59
    <compatibility addition="yes" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
60
    <description>
61
        <p>The method is called when CloneableOpenSupportRedirector found another instance of CloneableOpenSupport to open instead the current. 
62
        It is possible to override afterRedirect in derived classes and handle this situation.
63
        </p>
64
    </description>
65
    <class package="org.openide.windows" name="CloneableOpenSupport"/>
66
    <issue number="241991"/>
67
</change>    
53
<change id="WinSysBrandingOverride">
68
<change id="WinSysBrandingOverride">
54
    <api name="winsys"/>
69
    <api name="winsys"/>
55
    <summary>Override window system branding properties</summary>
70
    <summary>Override window system branding properties</summary>
(-)a/openide.windows/manifest.mf (-1 / +1 lines)
Lines 1-6 Link Here
1
Manifest-Version: 1.0
1
Manifest-Version: 1.0
2
OpenIDE-Module: org.openide.windows
2
OpenIDE-Module: org.openide.windows
3
OpenIDE-Module-Specification-Version: 6.69
3
OpenIDE-Module-Specification-Version: 6.70
4
OpenIDE-Module-Localizing-Bundle: org/openide/windows/Bundle.properties
4
OpenIDE-Module-Localizing-Bundle: org/openide/windows/Bundle.properties
5
AutoUpdate-Essential-Module: true
5
AutoUpdate-Essential-Module: true
6
6
(-)a/openide.windows/src/org/openide/windows/CloneableOpenSupport.java (+25 lines)
Lines 97-102 Link Here
97
        CloneableOpenSupport redirect = CloneableOpenSupportRedirector.findRedirect(this);
97
        CloneableOpenSupport redirect = CloneableOpenSupportRedirector.findRedirect(this);
98
        if (redirect != null) {
98
        if (redirect != null) {
99
            redirect.open();
99
            redirect.open();
100
            this.afterRedirectImpl(redirect);
100
            return;
101
            return;
101
        }
102
        }
102
        //Bugfix #10688 open() is now run in AWT thread
103
        //Bugfix #10688 open() is now run in AWT thread
Lines 246-251 Link Here
246
    */
247
    */
247
    protected abstract String messageOpened();
248
    protected abstract String messageOpened();
248
249
250
    private void afterRedirectImpl(CloneableOpenSupport redirectedTo) {
251
        // there is a common patern in user code:
252
        // CloneableEditorSupport ces = ...;
253
        // ces.edit();
254
        // JEditorPane[] panes = ces.getOpenedPanes();
255
        // if (panes != null) panes[0].setPosition(offset);
256
        // in case when redirection has happened during edit() call
257
        // 'ces' instance returns null for getOpenedPanes
258
        // but we want panes to be available for 'ces' instance after redirection;
259
        // remember editors from redirected instance to have correct opened panes
260
        // for this instance as well
261
        this.allEditors = redirectedTo.allEditors;
262
//        this.env = redirect.env;
263
        afterRedirect(redirectedTo);
264
    }
265
    
266
    /**
267
     * Called to notify that another redirected CloneableOpenSupport was opened instead of this one.
268
     * @param redirectedTo redirected instance which was opened instead of this one
269
     * @since 6.70
270
     */
271
    protected void afterRedirect(CloneableOpenSupport redirectedTo) {
272
    }
273
249
    /** Abstract interface that is used by CloneableOpenSupport to
274
    /** Abstract interface that is used by CloneableOpenSupport to
250
    * talk to outside world.
275
    * talk to outside world.
251
    */
276
    */

Return to bug 241991